1268e72f9Sdrh /* 2268e72f9Sdrh ** 2015-04-17 3268e72f9Sdrh ** 4268e72f9Sdrh ** The author disclaims copyright to this source code. In place of 5268e72f9Sdrh ** a legal notice, here is a blessing: 6268e72f9Sdrh ** 7268e72f9Sdrh ** May you do good and not evil. 8268e72f9Sdrh ** May you find forgiveness for yourself and forgive others. 9268e72f9Sdrh ** May you share freely, never taking more than you give. 10268e72f9Sdrh ** 11268e72f9Sdrh ************************************************************************* 12268e72f9Sdrh ** 13268e72f9Sdrh ** This is a utility program designed to aid running the SQLite library 14268e72f9Sdrh ** against an external fuzzer, such as American Fuzzy Lop (AFL) 15268e72f9Sdrh ** (http://lcamtuf.coredump.cx/afl/). Basically, this program reads 16268e72f9Sdrh ** SQL text from standard input and passes it through to SQLite for evaluation, 17268e72f9Sdrh ** just like the "sqlite3" command-line shell. Differences from the 18268e72f9Sdrh ** command-line shell: 19268e72f9Sdrh ** 20268e72f9Sdrh ** (1) The complex "dot-command" extensions are omitted. This 21268e72f9Sdrh ** prevents the fuzzer from discovering that it can run things 22268e72f9Sdrh ** like ".shell rm -rf ~" 23268e72f9Sdrh ** 24268e72f9Sdrh ** (2) The database is opened with the SQLITE_OPEN_MEMORY flag so that 25268e72f9Sdrh ** no disk I/O from the database is permitted. The ATTACH command 26268e72f9Sdrh ** with a filename still uses an in-memory database. 27268e72f9Sdrh ** 28268e72f9Sdrh ** (3) The main in-memory database can be initialized from a template 29268e72f9Sdrh ** disk database so that the fuzzer starts with a database containing 30268e72f9Sdrh ** content. 31268e72f9Sdrh ** 32268e72f9Sdrh ** (4) The eval() SQL function is added, allowing the fuzzer to do 33268e72f9Sdrh ** interesting recursive operations. 34f34e9aabSdrh ** 35be5248f0Sdrh ** (5) An error is raised if there is a memory leak. 36be5248f0Sdrh ** 37be5248f0Sdrh ** The input text can be divided into separate test cases using comments 38be5248f0Sdrh ** of the form: 39f34e9aabSdrh ** 40f34e9aabSdrh ** |****<...>****| 41f34e9aabSdrh ** 42f332071bSdrh ** where the "..." is arbitrary text. (Except the "|" should really be "/". 43f332071bSdrh ** "|" is used here to avoid compiler errors about nested comments.) 44be5248f0Sdrh ** A separate in-memory SQLite database is created to run each test case. 45875bafa1Sdrh ** This feature allows the "queue" of AFL to be captured into a single big 46f34e9aabSdrh ** file using a command like this: 47f34e9aabSdrh ** 48f34e9aabSdrh ** (for i in id:*; do echo '|****<'$i'>****|'; cat $i; done) >~/all-queue.txt 49f34e9aabSdrh ** 50f34e9aabSdrh ** (Once again, change the "|" to "/") Then all elements of the AFL queue 514a74d076Sdrh ** can be run in a single go (for regression testing, for example) by typing: 52f34e9aabSdrh ** 53875bafa1Sdrh ** fuzzershell -f ~/all-queue.txt 54f34e9aabSdrh ** 55f34e9aabSdrh ** After running each chunk of SQL, the database connection is closed. The 56f34e9aabSdrh ** program aborts if the close fails or if there is any unfreed memory after 57f34e9aabSdrh ** the close. 58875bafa1Sdrh ** 59be5248f0Sdrh ** New test cases can be appended to all-queue.txt at any time. If redundant 60be5248f0Sdrh ** test cases are added, they can be eliminated by running: 61875bafa1Sdrh ** 62875bafa1Sdrh ** fuzzershell -f ~/all-queue.txt --unique-cases ~/unique-cases.txt 63268e72f9Sdrh */ 64268e72f9Sdrh #include <stdio.h> 65268e72f9Sdrh #include <stdlib.h> 66268e72f9Sdrh #include <string.h> 67268e72f9Sdrh #include <stdarg.h> 684a74d076Sdrh #include <ctype.h> 69268e72f9Sdrh #include "sqlite3.h" 70268e72f9Sdrh 71268e72f9Sdrh /* 72268e72f9Sdrh ** All global variables are gathered into the "g" singleton. 73268e72f9Sdrh */ 74268e72f9Sdrh struct GlobalVars { 75268e72f9Sdrh const char *zArgv0; /* Name of program */ 76048810b6Sdrh sqlite3_mem_methods sOrigMem; /* Original memory methods */ 77048810b6Sdrh sqlite3_mem_methods sOomMem; /* Memory methods with OOM simulator */ 78048810b6Sdrh int iOomCntdown; /* Memory fails on 1 to 0 transition */ 79048810b6Sdrh int nOomFault; /* Increments for each OOM fault */ 80048810b6Sdrh int bOomOnce; /* Fail just once if true */ 81048810b6Sdrh int bOomEnable; /* True to enable OOM simulation */ 82048810b6Sdrh int nOomBrkpt; /* Number of calls to oomFault() */ 830ee751fbSdrh char zTestName[100]; /* Name of current test */ 84268e72f9Sdrh } g; 85268e72f9Sdrh 86048810b6Sdrh /* 87f332071bSdrh ** Maximum number of iterations for an OOM test 88f332071bSdrh */ 89f332071bSdrh #ifndef OOM_MAX 907c84c02cSdrh # define OOM_MAX 625 91f332071bSdrh #endif 92f332071bSdrh 93f332071bSdrh /* 94048810b6Sdrh ** This routine is called when a simulated OOM occurs. It exists as a 95048810b6Sdrh ** convenient place to set a debugger breakpoint. 96048810b6Sdrh */ 97048810b6Sdrh static void oomFault(void){ 98be5248f0Sdrh g.nOomBrkpt++; /* Prevent oomFault() from being optimized out */ 99048810b6Sdrh } 100268e72f9Sdrh 101268e72f9Sdrh 102048810b6Sdrh /* Versions of malloc() and realloc() that simulate OOM conditions */ 103048810b6Sdrh static void *oomMalloc(int nByte){ 104048810b6Sdrh if( nByte>0 && g.bOomEnable && g.iOomCntdown>0 ){ 105048810b6Sdrh g.iOomCntdown--; 106048810b6Sdrh if( g.iOomCntdown==0 ){ 107048810b6Sdrh if( g.nOomFault==0 ) oomFault(); 108048810b6Sdrh g.nOomFault++; 109048810b6Sdrh if( !g.bOomOnce ) g.iOomCntdown = 1; 110048810b6Sdrh return 0; 111048810b6Sdrh } 112048810b6Sdrh } 113048810b6Sdrh return g.sOrigMem.xMalloc(nByte); 114048810b6Sdrh } 115048810b6Sdrh static void *oomRealloc(void *pOld, int nByte){ 116048810b6Sdrh if( nByte>0 && g.bOomEnable && g.iOomCntdown>0 ){ 117048810b6Sdrh g.iOomCntdown--; 118048810b6Sdrh if( g.iOomCntdown==0 ){ 119048810b6Sdrh if( g.nOomFault==0 ) oomFault(); 120048810b6Sdrh g.nOomFault++; 121048810b6Sdrh if( !g.bOomOnce ) g.iOomCntdown = 1; 122048810b6Sdrh return 0; 123048810b6Sdrh } 124048810b6Sdrh } 125048810b6Sdrh return g.sOrigMem.xRealloc(pOld, nByte); 126048810b6Sdrh } 127048810b6Sdrh 128268e72f9Sdrh /* 129268e72f9Sdrh ** Print an error message and abort in such a way to indicate to the 130268e72f9Sdrh ** fuzzer that this counts as a crash. 131268e72f9Sdrh */ 132268e72f9Sdrh static void abendError(const char *zFormat, ...){ 133268e72f9Sdrh va_list ap; 134be5248f0Sdrh if( g.zTestName[0] ){ 135be5248f0Sdrh fprintf(stderr, "%s (%s): ", g.zArgv0, g.zTestName); 136be5248f0Sdrh }else{ 137268e72f9Sdrh fprintf(stderr, "%s: ", g.zArgv0); 138be5248f0Sdrh } 139268e72f9Sdrh va_start(ap, zFormat); 140268e72f9Sdrh vfprintf(stderr, zFormat, ap); 141268e72f9Sdrh va_end(ap); 142268e72f9Sdrh fprintf(stderr, "\n"); 143268e72f9Sdrh abort(); 144268e72f9Sdrh } 145268e72f9Sdrh /* 146268e72f9Sdrh ** Print an error message and quit, but not in a way that would look 147268e72f9Sdrh ** like a crash. 148268e72f9Sdrh */ 149268e72f9Sdrh static void fatalError(const char *zFormat, ...){ 150268e72f9Sdrh va_list ap; 151be5248f0Sdrh if( g.zTestName[0] ){ 152be5248f0Sdrh fprintf(stderr, "%s (%s): ", g.zArgv0, g.zTestName); 153be5248f0Sdrh }else{ 154268e72f9Sdrh fprintf(stderr, "%s: ", g.zArgv0); 155be5248f0Sdrh } 156268e72f9Sdrh va_start(ap, zFormat); 157268e72f9Sdrh vfprintf(stderr, zFormat, ap); 158268e72f9Sdrh va_end(ap); 159268e72f9Sdrh fprintf(stderr, "\n"); 160268e72f9Sdrh exit(1); 161268e72f9Sdrh } 162268e72f9Sdrh 163268e72f9Sdrh /* 1644a74d076Sdrh ** Evaluate some SQL. Abort if unable. 1654a74d076Sdrh */ 1664a74d076Sdrh static void sqlexec(sqlite3 *db, const char *zFormat, ...){ 1674a74d076Sdrh va_list ap; 1684a74d076Sdrh char *zSql; 1694a74d076Sdrh char *zErrMsg = 0; 1704a74d076Sdrh int rc; 1714a74d076Sdrh va_start(ap, zFormat); 1724a74d076Sdrh zSql = sqlite3_vmprintf(zFormat, ap); 1734a74d076Sdrh va_end(ap); 1744a74d076Sdrh rc = sqlite3_exec(db, zSql, 0, 0, &zErrMsg); 1754a74d076Sdrh if( rc ) abendError("failed sql [%s]: %s", zSql, zErrMsg); 1764a74d076Sdrh sqlite3_free(zSql); 1774a74d076Sdrh } 1784a74d076Sdrh 1794a74d076Sdrh /* 180268e72f9Sdrh ** This callback is invoked by sqlite3_log(). 181268e72f9Sdrh */ 182268e72f9Sdrh static void shellLog(void *pNotUsed, int iErrCode, const char *zMsg){ 183268e72f9Sdrh printf("LOG: (%d) %s\n", iErrCode, zMsg); 1849f18f743Sdrh fflush(stdout); 185268e72f9Sdrh } 1860ee751fbSdrh static void shellLogNoop(void *pNotUsed, int iErrCode, const char *zMsg){ 1870ee751fbSdrh return; 1880ee751fbSdrh } 189268e72f9Sdrh 190268e72f9Sdrh /* 191268e72f9Sdrh ** This callback is invoked by sqlite3_exec() to return query results. 192268e72f9Sdrh */ 193268e72f9Sdrh static int execCallback(void *NotUsed, int argc, char **argv, char **colv){ 194268e72f9Sdrh int i; 195268e72f9Sdrh static unsigned cnt = 0; 196268e72f9Sdrh printf("ROW #%u:\n", ++cnt); 197268e72f9Sdrh for(i=0; i<argc; i++){ 198268e72f9Sdrh printf(" %s=", colv[i]); 199268e72f9Sdrh if( argv[i] ){ 200268e72f9Sdrh printf("[%s]\n", argv[i]); 201268e72f9Sdrh }else{ 202268e72f9Sdrh printf("NULL\n"); 203268e72f9Sdrh } 204268e72f9Sdrh } 2059f18f743Sdrh fflush(stdout); 206268e72f9Sdrh return 0; 207268e72f9Sdrh } 2081cbb7fa9Sdrh static int execNoop(void *NotUsed, int argc, char **argv, char **colv){ 2091cbb7fa9Sdrh return 0; 2101cbb7fa9Sdrh } 211268e72f9Sdrh 21261a0d6bcSdrh #ifndef SQLITE_OMIT_TRACE 213268e72f9Sdrh /* 214268e72f9Sdrh ** This callback is invoked by sqlite3_trace() as each SQL statement 215268e72f9Sdrh ** starts. 216268e72f9Sdrh */ 217268e72f9Sdrh static void traceCallback(void *NotUsed, const char *zMsg){ 218268e72f9Sdrh printf("TRACE: %s\n", zMsg); 2199f18f743Sdrh fflush(stdout); 220268e72f9Sdrh } 2210ee751fbSdrh static void traceNoop(void *NotUsed, const char *zMsg){ 2220ee751fbSdrh return; 2230ee751fbSdrh } 22461a0d6bcSdrh #endif 225268e72f9Sdrh 226268e72f9Sdrh /*************************************************************************** 227268e72f9Sdrh ** eval() implementation copied from ../ext/misc/eval.c 228268e72f9Sdrh */ 229268e72f9Sdrh /* 230268e72f9Sdrh ** Structure used to accumulate the output 231268e72f9Sdrh */ 232268e72f9Sdrh struct EvalResult { 233268e72f9Sdrh char *z; /* Accumulated output */ 234268e72f9Sdrh const char *zSep; /* Separator */ 235268e72f9Sdrh int szSep; /* Size of the separator string */ 236268e72f9Sdrh sqlite3_int64 nAlloc; /* Number of bytes allocated for z[] */ 237268e72f9Sdrh sqlite3_int64 nUsed; /* Number of bytes of z[] actually used */ 238268e72f9Sdrh }; 239268e72f9Sdrh 240268e72f9Sdrh /* 241268e72f9Sdrh ** Callback from sqlite_exec() for the eval() function. 242268e72f9Sdrh */ 243268e72f9Sdrh static int callback(void *pCtx, int argc, char **argv, char **colnames){ 244268e72f9Sdrh struct EvalResult *p = (struct EvalResult*)pCtx; 245268e72f9Sdrh int i; 246268e72f9Sdrh for(i=0; i<argc; i++){ 247268e72f9Sdrh const char *z = argv[i] ? argv[i] : ""; 248268e72f9Sdrh size_t sz = strlen(z); 249268e72f9Sdrh if( (sqlite3_int64)sz+p->nUsed+p->szSep+1 > p->nAlloc ){ 250268e72f9Sdrh char *zNew; 251268e72f9Sdrh p->nAlloc = p->nAlloc*2 + sz + p->szSep + 1; 252268e72f9Sdrh /* Using sqlite3_realloc64() would be better, but it is a recent 253268e72f9Sdrh ** addition and will cause a segfault if loaded by an older version 254268e72f9Sdrh ** of SQLite. */ 255268e72f9Sdrh zNew = p->nAlloc<=0x7fffffff ? sqlite3_realloc(p->z, (int)p->nAlloc) : 0; 256268e72f9Sdrh if( zNew==0 ){ 257268e72f9Sdrh sqlite3_free(p->z); 258268e72f9Sdrh memset(p, 0, sizeof(*p)); 259268e72f9Sdrh return 1; 260268e72f9Sdrh } 261268e72f9Sdrh p->z = zNew; 262268e72f9Sdrh } 263268e72f9Sdrh if( p->nUsed>0 ){ 264268e72f9Sdrh memcpy(&p->z[p->nUsed], p->zSep, p->szSep); 265268e72f9Sdrh p->nUsed += p->szSep; 266268e72f9Sdrh } 267268e72f9Sdrh memcpy(&p->z[p->nUsed], z, sz); 268268e72f9Sdrh p->nUsed += sz; 269268e72f9Sdrh } 270268e72f9Sdrh return 0; 271268e72f9Sdrh } 272268e72f9Sdrh 273268e72f9Sdrh /* 274268e72f9Sdrh ** Implementation of the eval(X) and eval(X,Y) SQL functions. 275268e72f9Sdrh ** 276268e72f9Sdrh ** Evaluate the SQL text in X. Return the results, using string 277268e72f9Sdrh ** Y as the separator. If Y is omitted, use a single space character. 278268e72f9Sdrh */ 279268e72f9Sdrh static void sqlEvalFunc( 280268e72f9Sdrh sqlite3_context *context, 281268e72f9Sdrh int argc, 282268e72f9Sdrh sqlite3_value **argv 283268e72f9Sdrh ){ 284268e72f9Sdrh const char *zSql; 285268e72f9Sdrh sqlite3 *db; 286268e72f9Sdrh char *zErr = 0; 287268e72f9Sdrh int rc; 288268e72f9Sdrh struct EvalResult x; 289268e72f9Sdrh 290268e72f9Sdrh memset(&x, 0, sizeof(x)); 291268e72f9Sdrh x.zSep = " "; 292268e72f9Sdrh zSql = (const char*)sqlite3_value_text(argv[0]); 293268e72f9Sdrh if( zSql==0 ) return; 294268e72f9Sdrh if( argc>1 ){ 295268e72f9Sdrh x.zSep = (const char*)sqlite3_value_text(argv[1]); 296268e72f9Sdrh if( x.zSep==0 ) return; 297268e72f9Sdrh } 298268e72f9Sdrh x.szSep = (int)strlen(x.zSep); 299268e72f9Sdrh db = sqlite3_context_db_handle(context); 300268e72f9Sdrh rc = sqlite3_exec(db, zSql, callback, &x, &zErr); 301268e72f9Sdrh if( rc!=SQLITE_OK ){ 302268e72f9Sdrh sqlite3_result_error(context, zErr, -1); 303268e72f9Sdrh sqlite3_free(zErr); 304268e72f9Sdrh }else if( x.zSep==0 ){ 305268e72f9Sdrh sqlite3_result_error_nomem(context); 306268e72f9Sdrh sqlite3_free(x.z); 307268e72f9Sdrh }else{ 308268e72f9Sdrh sqlite3_result_text(context, x.z, (int)x.nUsed, sqlite3_free); 309268e72f9Sdrh } 310268e72f9Sdrh } 311268e72f9Sdrh /* End of the eval() implementation 312268e72f9Sdrh ******************************************************************************/ 313268e72f9Sdrh 314268e72f9Sdrh /* 315268e72f9Sdrh ** Print sketchy documentation for this utility program 316268e72f9Sdrh */ 317268e72f9Sdrh static void showHelp(void){ 318b3df0c67Sdrh printf("Usage: %s [options] ?FILE...?\n", g.zArgv0); 319268e72f9Sdrh printf( 320b3df0c67Sdrh "Read SQL text from FILE... (or from standard input if FILE... is omitted)\n" 321b3df0c67Sdrh "and then evaluate each block of SQL contained therein.\n" 322268e72f9Sdrh "Options:\n" 3234a74d076Sdrh " --autovacuum Enable AUTOVACUUM mode\n" 324acd33745Sdrh " --database FILE Use database FILE instead of an in-memory database\n" 3254a74d076Sdrh " --heap SZ MIN Memory allocator uses SZ bytes & min allocation MIN\n" 326268e72f9Sdrh " --help Show this help text\n" 3274a74d076Sdrh " --lookaside N SZ Configure lookaside for N slots of SZ bytes each\n" 328048810b6Sdrh " --oom Run each test multiple times in a simulated OOM loop\n" 3294a74d076Sdrh " --pagesize N Set the page size to N\n" 3304a74d076Sdrh " --pcache N SZ Configure N pages of pagecache each of size SZ bytes\n" 3311cbb7fa9Sdrh " -q Reduced output\n" 3321cbb7fa9Sdrh " --quiet Reduced output\n" 3334a74d076Sdrh " --scratch N SZ Configure scratch memory for N slots of SZ bytes each\n" 334875bafa1Sdrh " --unique-cases FILE Write all unique test cases to FILE\n" 3354a74d076Sdrh " --utf16be Set text encoding to UTF-16BE\n" 3364a74d076Sdrh " --utf16le Set text encoding to UTF-16LE\n" 3371cbb7fa9Sdrh " -v Increased output\n" 3381cbb7fa9Sdrh " --verbose Increased output\n" 339268e72f9Sdrh ); 340268e72f9Sdrh } 341268e72f9Sdrh 3424a74d076Sdrh /* 3434a74d076Sdrh ** Return the value of a hexadecimal digit. Return -1 if the input 3444a74d076Sdrh ** is not a hex digit. 3454a74d076Sdrh */ 3464a74d076Sdrh static int hexDigitValue(char c){ 3474a74d076Sdrh if( c>='0' && c<='9' ) return c - '0'; 3484a74d076Sdrh if( c>='a' && c<='f' ) return c - 'a' + 10; 3494a74d076Sdrh if( c>='A' && c<='F' ) return c - 'A' + 10; 3504a74d076Sdrh return -1; 3514a74d076Sdrh } 3524a74d076Sdrh 3534a74d076Sdrh /* 3544a74d076Sdrh ** Interpret zArg as an integer value, possibly with suffixes. 3554a74d076Sdrh */ 3564a74d076Sdrh static int integerValue(const char *zArg){ 3574a74d076Sdrh sqlite3_int64 v = 0; 3584a74d076Sdrh static const struct { char *zSuffix; int iMult; } aMult[] = { 3594a74d076Sdrh { "KiB", 1024 }, 3604a74d076Sdrh { "MiB", 1024*1024 }, 3614a74d076Sdrh { "GiB", 1024*1024*1024 }, 3624a74d076Sdrh { "KB", 1000 }, 3634a74d076Sdrh { "MB", 1000000 }, 3644a74d076Sdrh { "GB", 1000000000 }, 3654a74d076Sdrh { "K", 1000 }, 3664a74d076Sdrh { "M", 1000000 }, 3674a74d076Sdrh { "G", 1000000000 }, 3684a74d076Sdrh }; 3694a74d076Sdrh int i; 3704a74d076Sdrh int isNeg = 0; 3714a74d076Sdrh if( zArg[0]=='-' ){ 3724a74d076Sdrh isNeg = 1; 3734a74d076Sdrh zArg++; 3744a74d076Sdrh }else if( zArg[0]=='+' ){ 3754a74d076Sdrh zArg++; 3764a74d076Sdrh } 3774a74d076Sdrh if( zArg[0]=='0' && zArg[1]=='x' ){ 3784a74d076Sdrh int x; 3794a74d076Sdrh zArg += 2; 3804a74d076Sdrh while( (x = hexDigitValue(zArg[0]))>=0 ){ 3814a74d076Sdrh v = (v<<4) + x; 3824a74d076Sdrh zArg++; 3834a74d076Sdrh } 3844a74d076Sdrh }else{ 3854a74d076Sdrh while( isdigit(zArg[0]) ){ 3864a74d076Sdrh v = v*10 + zArg[0] - '0'; 3874a74d076Sdrh zArg++; 3884a74d076Sdrh } 3894a74d076Sdrh } 3904a74d076Sdrh for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){ 3914a74d076Sdrh if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){ 3924a74d076Sdrh v *= aMult[i].iMult; 3934a74d076Sdrh break; 3944a74d076Sdrh } 3954a74d076Sdrh } 3964a74d076Sdrh if( v>0x7fffffff ) abendError("parameter too large - max 2147483648"); 3974a74d076Sdrh return (int)(isNeg? -v : v); 3984a74d076Sdrh } 3994a74d076Sdrh 400c843016eSdrh /* Return the current wall-clock time */ 401c843016eSdrh static sqlite3_int64 timeOfDay(void){ 402c843016eSdrh static sqlite3_vfs *clockVfs = 0; 403c843016eSdrh sqlite3_int64 t; 404c843016eSdrh if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0); 405c843016eSdrh if( clockVfs->iVersion>=1 && clockVfs->xCurrentTimeInt64!=0 ){ 406c843016eSdrh clockVfs->xCurrentTimeInt64(clockVfs, &t); 407c843016eSdrh }else{ 408c843016eSdrh double r; 409c843016eSdrh clockVfs->xCurrentTime(clockVfs, &r); 410c843016eSdrh t = (sqlite3_int64)(r*86400000.0); 411c843016eSdrh } 412c843016eSdrh return t; 413c843016eSdrh } 414268e72f9Sdrh 415268e72f9Sdrh int main(int argc, char **argv){ 416268e72f9Sdrh char *zIn = 0; /* Input text */ 417268e72f9Sdrh int nAlloc = 0; /* Number of bytes allocated for zIn[] */ 418268e72f9Sdrh int nIn = 0; /* Number of bytes of zIn[] used */ 419268e72f9Sdrh size_t got; /* Bytes read from input */ 420268e72f9Sdrh int rc = SQLITE_OK; /* Result codes from API functions */ 421268e72f9Sdrh int i; /* Loop counter */ 422f34e9aabSdrh int iNext; /* Next block of SQL */ 423268e72f9Sdrh sqlite3 *db; /* Open database */ 424268e72f9Sdrh char *zErrMsg = 0; /* Error message returned from sqlite3_exec() */ 4254a74d076Sdrh const char *zEncoding = 0; /* --utf16be or --utf16le */ 4264a74d076Sdrh int nHeap = 0, mnHeap = 0; /* Heap size from --heap */ 4274a74d076Sdrh int nLook = 0, szLook = 0; /* --lookaside configuration */ 4284a74d076Sdrh int nPCache = 0, szPCache = 0;/* --pcache configuration */ 4294a74d076Sdrh int nScratch = 0, szScratch=0;/* --scratch configuration */ 4304a74d076Sdrh int pageSize = 0; /* Desired page size. 0 means default */ 4314a74d076Sdrh void *pHeap = 0; /* Allocated heap space */ 4324a74d076Sdrh void *pLook = 0; /* Allocated lookaside space */ 4334a74d076Sdrh void *pPCache = 0; /* Allocated storage for pcache */ 4344a74d076Sdrh void *pScratch = 0; /* Allocated storage for scratch */ 4354a74d076Sdrh int doAutovac = 0; /* True for --autovacuum */ 4369985dabbSdrh char *zSql; /* SQL to run */ 4379985dabbSdrh char *zToFree = 0; /* Call sqlite3_free() on this afte running zSql */ 4381cbb7fa9Sdrh int verboseFlag = 0; /* --verbose or -v flag */ 4391cbb7fa9Sdrh int quietFlag = 0; /* --quiet or -q flag */ 4401cbb7fa9Sdrh int nTest = 0; /* Number of test cases run */ 4411cbb7fa9Sdrh int multiTest = 0; /* True if there will be multiple test cases */ 4421cbb7fa9Sdrh int lastPct = -1; /* Previous percentage done output */ 443875bafa1Sdrh sqlite3 *dataDb = 0; /* Database holding compacted input data */ 444875bafa1Sdrh sqlite3_stmt *pStmt = 0; /* Statement to insert testcase into dataDb */ 445875bafa1Sdrh const char *zDataOut = 0; /* Write compacted data to this output file */ 446e1a71a58Sdrh int nHeader = 0; /* Bytes of header comment text on input file */ 447048810b6Sdrh int oomFlag = 0; /* --oom */ 448048810b6Sdrh int oomCnt = 0; /* Counter for the OOM loop */ 449048810b6Sdrh char zErrBuf[200]; /* Space for the error message */ 450048810b6Sdrh const char *zFailCode; /* Value of the TEST_FAILURE environment var */ 451b3df0c67Sdrh const char *zPrompt; /* Initial prompt when large-file fuzzing */ 452b3df0c67Sdrh int nInFile = 0; /* Number of input files to read */ 453b3df0c67Sdrh char **azInFile = 0; /* Array of input file names */ 454b3df0c67Sdrh int jj; /* Loop counter for azInFile[] */ 4551a57c17dSdrh sqlite3_int64 iBegin; /* Start time for the whole program */ 456c843016eSdrh sqlite3_int64 iStart, iEnd; /* Start and end-times for a test case */ 457f9def061Sdrh const char *zDbName = 0; /* Name of an on-disk database file to open */ 4584a74d076Sdrh 4591a57c17dSdrh iBegin = timeOfDay(); 460048810b6Sdrh zFailCode = getenv("TEST_FAILURE"); 461268e72f9Sdrh g.zArgv0 = argv[0]; 462b3df0c67Sdrh zPrompt = "<stdin>"; 463268e72f9Sdrh for(i=1; i<argc; i++){ 464268e72f9Sdrh const char *z = argv[i]; 465268e72f9Sdrh if( z[0]=='-' ){ 466268e72f9Sdrh z++; 467268e72f9Sdrh if( z[0]=='-' ) z++; 4684a74d076Sdrh if( strcmp(z,"autovacuum")==0 ){ 4694a74d076Sdrh doAutovac = 1; 470268e72f9Sdrh }else 471acd33745Sdrh if( strcmp(z,"database")==0 ){ 472acd33745Sdrh if( i>=argc-1 ) abendError("missing argument on %s\n", argv[i]); 473acd33745Sdrh zDbName = argv[i+1]; 474acd33745Sdrh i += 1; 475acd33745Sdrh }else 476268e72f9Sdrh if( strcmp(z, "f")==0 && i+1<argc ){ 477b3df0c67Sdrh i++; 478b3df0c67Sdrh goto addNewInFile; 479268e72f9Sdrh }else 4804a74d076Sdrh if( strcmp(z,"heap")==0 ){ 4814a74d076Sdrh if( i>=argc-2 ) abendError("missing arguments on %s\n", argv[i]); 4824a74d076Sdrh nHeap = integerValue(argv[i+1]); 4834a74d076Sdrh mnHeap = integerValue(argv[i+2]); 4844a74d076Sdrh i += 2; 4854a74d076Sdrh }else 4864a74d076Sdrh if( strcmp(z,"help")==0 ){ 4874a74d076Sdrh showHelp(); 4884a74d076Sdrh return 0; 4894a74d076Sdrh }else 4904a74d076Sdrh if( strcmp(z,"lookaside")==0 ){ 4914a74d076Sdrh if( i>=argc-2 ) abendError("missing arguments on %s", argv[i]); 4924a74d076Sdrh nLook = integerValue(argv[i+1]); 4934a74d076Sdrh szLook = integerValue(argv[i+2]); 4944a74d076Sdrh i += 2; 4954a74d076Sdrh }else 496048810b6Sdrh if( strcmp(z,"oom")==0 ){ 497048810b6Sdrh oomFlag = 1; 498048810b6Sdrh }else 4994a74d076Sdrh if( strcmp(z,"pagesize")==0 ){ 5004a74d076Sdrh if( i>=argc-1 ) abendError("missing argument on %s", argv[i]); 5014a74d076Sdrh pageSize = integerValue(argv[++i]); 5024a74d076Sdrh }else 5034a74d076Sdrh if( strcmp(z,"pcache")==0 ){ 5044a74d076Sdrh if( i>=argc-2 ) abendError("missing arguments on %s", argv[i]); 5054a74d076Sdrh nPCache = integerValue(argv[i+1]); 5064a74d076Sdrh szPCache = integerValue(argv[i+2]); 5074a74d076Sdrh i += 2; 5084a74d076Sdrh }else 5091cbb7fa9Sdrh if( strcmp(z,"quiet")==0 || strcmp(z,"q")==0 ){ 5101cbb7fa9Sdrh quietFlag = 1; 5111cbb7fa9Sdrh verboseFlag = 0; 5121cbb7fa9Sdrh }else 5134a74d076Sdrh if( strcmp(z,"scratch")==0 ){ 5144a74d076Sdrh if( i>=argc-2 ) abendError("missing arguments on %s", argv[i]); 5154a74d076Sdrh nScratch = integerValue(argv[i+1]); 5164a74d076Sdrh szScratch = integerValue(argv[i+2]); 5174a74d076Sdrh i += 2; 5184a74d076Sdrh }else 519875bafa1Sdrh if( strcmp(z, "unique-cases")==0 ){ 520875bafa1Sdrh if( i>=argc-1 ) abendError("missing arguments on %s", argv[i]); 521875bafa1Sdrh if( zDataOut ) abendError("only one --minimize allowed"); 522875bafa1Sdrh zDataOut = argv[++i]; 523875bafa1Sdrh }else 5244a74d076Sdrh if( strcmp(z,"utf16le")==0 ){ 5254a74d076Sdrh zEncoding = "utf16le"; 5264a74d076Sdrh }else 5274a74d076Sdrh if( strcmp(z,"utf16be")==0 ){ 5284a74d076Sdrh zEncoding = "utf16be"; 5294a74d076Sdrh }else 5301cbb7fa9Sdrh if( strcmp(z,"verbose")==0 || strcmp(z,"v")==0 ){ 5311cbb7fa9Sdrh quietFlag = 0; 5321cbb7fa9Sdrh verboseFlag = 1; 5331cbb7fa9Sdrh }else 534268e72f9Sdrh { 535268e72f9Sdrh abendError("unknown option: %s", argv[i]); 536268e72f9Sdrh } 537268e72f9Sdrh }else{ 538b3df0c67Sdrh addNewInFile: 539b3df0c67Sdrh nInFile++; 540b3df0c67Sdrh azInFile = realloc(azInFile, sizeof(azInFile[0])*nInFile); 541b3df0c67Sdrh if( azInFile==0 ) abendError("out of memory"); 542b3df0c67Sdrh azInFile[nInFile-1] = argv[i]; 543268e72f9Sdrh } 544268e72f9Sdrh } 545b3df0c67Sdrh 546b3df0c67Sdrh /* Do global SQLite initialization */ 5470ee751fbSdrh sqlite3_config(SQLITE_CONFIG_LOG, verboseFlag ? shellLog : shellLogNoop, 0); 5484a74d076Sdrh if( nHeap>0 ){ 5494a74d076Sdrh pHeap = malloc( nHeap ); 5504a74d076Sdrh if( pHeap==0 ) fatalError("cannot allocate %d-byte heap\n", nHeap); 5514a74d076Sdrh rc = sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nHeap, mnHeap); 5524a74d076Sdrh if( rc ) abendError("heap configuration failed: %d\n", rc); 5534a74d076Sdrh } 554048810b6Sdrh if( oomFlag ){ 555048810b6Sdrh sqlite3_config(SQLITE_CONFIG_GETMALLOC, &g.sOrigMem); 556048810b6Sdrh g.sOomMem = g.sOrigMem; 557048810b6Sdrh g.sOomMem.xMalloc = oomMalloc; 558048810b6Sdrh g.sOomMem.xRealloc = oomRealloc; 559048810b6Sdrh sqlite3_config(SQLITE_CONFIG_MALLOC, &g.sOomMem); 560048810b6Sdrh } 5614a74d076Sdrh if( nLook>0 ){ 5624a74d076Sdrh sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0); 5634a74d076Sdrh if( szLook>0 ){ 5644a74d076Sdrh pLook = malloc( nLook*szLook ); 5654a74d076Sdrh if( pLook==0 ) fatalError("out of memory"); 5664a74d076Sdrh } 5674a74d076Sdrh } 5684a74d076Sdrh if( nScratch>0 && szScratch>0 ){ 5694a74d076Sdrh pScratch = malloc( nScratch*(sqlite3_int64)szScratch ); 5704a74d076Sdrh if( pScratch==0 ) fatalError("cannot allocate %lld-byte scratch", 5714a74d076Sdrh nScratch*(sqlite3_int64)szScratch); 5724a74d076Sdrh rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, pScratch, szScratch, nScratch); 5734a74d076Sdrh if( rc ) abendError("scratch configuration failed: %d\n", rc); 5744a74d076Sdrh } 5754a74d076Sdrh if( nPCache>0 && szPCache>0 ){ 5764a74d076Sdrh pPCache = malloc( nPCache*(sqlite3_int64)szPCache ); 5774a74d076Sdrh if( pPCache==0 ) fatalError("cannot allocate %lld-byte pcache", 5784a74d076Sdrh nPCache*(sqlite3_int64)szPCache); 5794a74d076Sdrh rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, pPCache, szPCache, nPCache); 5804a74d076Sdrh if( rc ) abendError("pcache configuration failed: %d", rc); 5814a74d076Sdrh } 582b3df0c67Sdrh 583b3df0c67Sdrh /* If the --unique-cases option was supplied, open the database that will 584b3df0c67Sdrh ** be used to gather unique test cases. 585b3df0c67Sdrh */ 586875bafa1Sdrh if( zDataOut ){ 587875bafa1Sdrh rc = sqlite3_open(":memory:", &dataDb); 588875bafa1Sdrh if( rc ) abendError("cannot open :memory: database"); 589875bafa1Sdrh rc = sqlite3_exec(dataDb, 590c843016eSdrh "CREATE TABLE testcase(sql BLOB PRIMARY KEY, tm) WITHOUT ROWID;",0,0,0); 591875bafa1Sdrh if( rc ) abendError("%s", sqlite3_errmsg(dataDb)); 592b3df0c67Sdrh rc = sqlite3_prepare_v2(dataDb, 593c843016eSdrh "INSERT OR IGNORE INTO testcase(sql,tm)VALUES(?1,?2)", 594875bafa1Sdrh -1, &pStmt, 0); 595875bafa1Sdrh if( rc ) abendError("%s", sqlite3_errmsg(dataDb)); 596875bafa1Sdrh } 597b3df0c67Sdrh 598b3df0c67Sdrh /* Initialize the input buffer used to hold SQL text */ 599b3df0c67Sdrh if( nInFile==0 ) nInFile = 1; 600b3df0c67Sdrh nAlloc = 1000; 601b3df0c67Sdrh zIn = malloc(nAlloc); 602b3df0c67Sdrh if( zIn==0 ) fatalError("out of memory"); 603b3df0c67Sdrh 604b3df0c67Sdrh /* Loop over all input files */ 605b3df0c67Sdrh for(jj=0; jj<nInFile; jj++){ 606b3df0c67Sdrh 607b3df0c67Sdrh /* Read the complete content of the next input file into zIn[] */ 608b3df0c67Sdrh FILE *in; 609b3df0c67Sdrh if( azInFile ){ 610b3df0c67Sdrh int j, k; 611b3df0c67Sdrh in = fopen(azInFile[jj],"rb"); 612b3df0c67Sdrh if( in==0 ){ 613b3df0c67Sdrh abendError("cannot open %s for reading", azInFile[jj]); 614f34e9aabSdrh } 615b3df0c67Sdrh zPrompt = azInFile[jj]; 616b3df0c67Sdrh for(j=k=0; zPrompt[j]; j++) if( zPrompt[j]=='/' ) k = j+1; 617b3df0c67Sdrh zPrompt += k; 618b3df0c67Sdrh }else{ 619b3df0c67Sdrh in = stdin; 620b3df0c67Sdrh zPrompt = "<stdin>"; 621f34e9aabSdrh } 622b3df0c67Sdrh while( !feof(in) ){ 623b3df0c67Sdrh got = fread(zIn+nIn, 1, nAlloc-nIn-1, in); 624b3df0c67Sdrh nIn += (int)got; 625b3df0c67Sdrh zIn[nIn] = 0; 626b3df0c67Sdrh if( got==0 ) break; 6271a57c17dSdrh if( nAlloc - nIn - 1 < 100 ){ 628b3df0c67Sdrh nAlloc += nAlloc+1000; 6291a57c17dSdrh zIn = realloc(zIn, nAlloc); 6301a57c17dSdrh if( zIn==0 ) fatalError("out of memory"); 6311a57c17dSdrh } 632b3df0c67Sdrh } 633b3df0c67Sdrh if( in!=stdin ) fclose(in); 634b3df0c67Sdrh lastPct = -1; 635b3df0c67Sdrh 636b3df0c67Sdrh /* Skip initial lines of the input file that begin with "#" */ 637b3df0c67Sdrh for(i=0; i<nIn; i=iNext+1){ 638e1a71a58Sdrh if( zIn[i]!='#' ) break; 639e1a71a58Sdrh for(iNext=i+1; iNext<nIn && zIn[iNext]!='\n'; iNext++){} 640e1a71a58Sdrh } 641e1a71a58Sdrh nHeader = i; 642b3df0c67Sdrh 643b3df0c67Sdrh /* Process all test cases contained within the input file. 644b3df0c67Sdrh */ 645b3df0c67Sdrh for(; i<nIn; i=iNext, nTest++, g.zTestName[0]=0){ 646f34e9aabSdrh char cSaved; 647f34e9aabSdrh if( strncmp(&zIn[i], "/****<",6)==0 ){ 648f34e9aabSdrh char *z = strstr(&zIn[i], ">****/"); 649f34e9aabSdrh if( z ){ 650f34e9aabSdrh z += 6; 651be5248f0Sdrh sqlite3_snprintf(sizeof(g.zTestName), g.zTestName, "%.*s", 652f332071bSdrh (int)(z-&zIn[i]) - 12, &zIn[i+6]); 6539f18f743Sdrh if( verboseFlag ){ 6549f18f743Sdrh printf("%.*s\n", (int)(z-&zIn[i]), &zIn[i]); 6559f18f743Sdrh fflush(stdout); 6569f18f743Sdrh } 657f34e9aabSdrh i += (int)(z-&zIn[i]); 6581cbb7fa9Sdrh multiTest = 1; 659f34e9aabSdrh } 660f34e9aabSdrh } 661f34e9aabSdrh for(iNext=i; iNext<nIn && strncmp(&zIn[iNext],"/****<",6)!=0; iNext++){} 6623fb2cc11Sdrh cSaved = zIn[iNext]; 6633fb2cc11Sdrh zIn[iNext] = 0; 664c843016eSdrh 665b3df0c67Sdrh 666b3df0c67Sdrh /* Print out the SQL of the next test case is --verbose is enabled 667b3df0c67Sdrh */ 668048810b6Sdrh zSql = &zIn[i]; 669048810b6Sdrh if( verboseFlag ){ 670048810b6Sdrh printf("INPUT (offset: %d, size: %d): [%s]\n", 671048810b6Sdrh i, (int)strlen(&zIn[i]), &zIn[i]); 672048810b6Sdrh }else if( multiTest && !quietFlag ){ 673f332071bSdrh if( oomFlag ){ 674f332071bSdrh printf("%s\n", g.zTestName); 675f332071bSdrh }else{ 676f332071bSdrh int pct = (10*iNext)/nIn; 677048810b6Sdrh if( pct!=lastPct ){ 678b3df0c67Sdrh if( lastPct<0 ) printf("%s:", zPrompt); 679f332071bSdrh printf(" %d%%", pct*10); 680048810b6Sdrh lastPct = pct; 681048810b6Sdrh } 682048810b6Sdrh } 6831a57c17dSdrh }else if( nInFile>1 ){ 6841a57c17dSdrh printf("%s\n", zPrompt); 685f332071bSdrh } 686f332071bSdrh fflush(stdout); 687b3df0c67Sdrh 688b3df0c67Sdrh /* Run the next test case. Run it multiple times in --oom mode 689b3df0c67Sdrh */ 690048810b6Sdrh if( oomFlag ){ 691048810b6Sdrh oomCnt = g.iOomCntdown = 1; 692048810b6Sdrh g.nOomFault = 0; 693048810b6Sdrh g.bOomOnce = 1; 6949f18f743Sdrh if( verboseFlag ){ 6959f18f743Sdrh printf("Once.%d\n", oomCnt); 6969f18f743Sdrh fflush(stdout); 6979f18f743Sdrh } 698048810b6Sdrh }else{ 699048810b6Sdrh oomCnt = 0; 700048810b6Sdrh } 701048810b6Sdrh do{ 702acd33745Sdrh if( zDbName ){ 703acd33745Sdrh rc = sqlite3_open_v2(zDbName, &db, SQLITE_OPEN_READWRITE, 0); 704*c19bc9b6Sdrh if( rc!=SQLITE_OK ){ 705*c19bc9b6Sdrh abendError("Cannot open database file %s", zDbName); 706*c19bc9b6Sdrh } 707acd33745Sdrh }else{ 708268e72f9Sdrh rc = sqlite3_open_v2( 709268e72f9Sdrh "main.db", &db, 710268e72f9Sdrh SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY, 711268e72f9Sdrh 0); 712268e72f9Sdrh if( rc!=SQLITE_OK ){ 713268e72f9Sdrh abendError("Unable to open the in-memory database"); 714268e72f9Sdrh } 715*c19bc9b6Sdrh } 7164a74d076Sdrh if( pLook ){ 7174a74d076Sdrh rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE,pLook,szLook,nLook); 7184a74d076Sdrh if( rc!=SQLITE_OK ) abendError("lookaside configuration filed: %d", rc); 7194a74d076Sdrh } 72061a0d6bcSdrh #ifndef SQLITE_OMIT_TRACE 7210ee751fbSdrh sqlite3_trace(db, verboseFlag ? traceCallback : traceNoop, 0); 72261a0d6bcSdrh #endif 723268e72f9Sdrh sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0); 724268e72f9Sdrh sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0); 725f34e9aabSdrh sqlite3_limit(db, SQLITE_LIMIT_LENGTH, 1000000); 7264a74d076Sdrh if( zEncoding ) sqlexec(db, "PRAGMA encoding=%s", zEncoding); 7274a74d076Sdrh if( pageSize ) sqlexec(db, "PRAGMA pagesize=%d", pageSize); 7284a74d076Sdrh if( doAutovac ) sqlexec(db, "PRAGMA auto_vacuum=FULL"); 729c843016eSdrh iStart = timeOfDay(); 730048810b6Sdrh g.bOomEnable = 1; 7311cbb7fa9Sdrh if( verboseFlag ){ 7321cbb7fa9Sdrh zErrMsg = 0; 733048810b6Sdrh rc = sqlite3_exec(db, zSql, execCallback, 0, &zErrMsg); 734048810b6Sdrh if( zErrMsg ){ 735048810b6Sdrh sqlite3_snprintf(sizeof(zErrBuf),zErrBuf,"%z", zErrMsg); 736048810b6Sdrh zErrMsg = 0; 737048810b6Sdrh } 738048810b6Sdrh }else { 739048810b6Sdrh rc = sqlite3_exec(db, zSql, execNoop, 0, 0); 740048810b6Sdrh } 741048810b6Sdrh g.bOomEnable = 0; 742c843016eSdrh iEnd = timeOfDay(); 743048810b6Sdrh rc = sqlite3_close(db); 744048810b6Sdrh if( rc ){ 745048810b6Sdrh abendError("sqlite3_close() failed with rc=%d", rc); 746048810b6Sdrh } 747c843016eSdrh if( !zDataOut && sqlite3_memory_used()>0 ){ 748048810b6Sdrh abendError("memory in use after close: %lld bytes",sqlite3_memory_used()); 749048810b6Sdrh } 750048810b6Sdrh if( oomFlag ){ 7517c84c02cSdrh /* Limit the number of iterations of the OOM loop to OOM_MAX. If the 7527c84c02cSdrh ** first pass (single failure) exceeds 2/3rds of OOM_MAX this skip the 7537c84c02cSdrh ** second pass (continuous failure after first) completely. */ 754f332071bSdrh if( g.nOomFault==0 || oomCnt>OOM_MAX ){ 7557c84c02cSdrh if( g.bOomOnce && oomCnt<=(OOM_MAX*2/3) ){ 756048810b6Sdrh oomCnt = g.iOomCntdown = 1; 757048810b6Sdrh g.bOomOnce = 0; 758048810b6Sdrh }else{ 759048810b6Sdrh oomCnt = 0; 760048810b6Sdrh } 761048810b6Sdrh }else{ 762048810b6Sdrh g.iOomCntdown = ++oomCnt; 763048810b6Sdrh g.nOomFault = 0; 764048810b6Sdrh } 765048810b6Sdrh if( oomCnt ){ 766048810b6Sdrh if( verboseFlag ){ 767048810b6Sdrh printf("%s.%d\n", g.bOomOnce ? "Once" : "Multi", oomCnt); 7689f18f743Sdrh fflush(stdout); 769048810b6Sdrh } 770048810b6Sdrh nTest++; 771048810b6Sdrh } 772048810b6Sdrh } 773048810b6Sdrh }while( oomCnt>0 ); 774b3df0c67Sdrh 775c843016eSdrh /* Store unique test cases in the in the dataDb database if the 776c843016eSdrh ** --unique-cases flag is present 777c843016eSdrh */ 778c843016eSdrh if( zDataOut ){ 779c843016eSdrh sqlite3_bind_blob(pStmt, 1, &zIn[i], iNext-i, SQLITE_STATIC); 780c843016eSdrh sqlite3_bind_int64(pStmt, 2, iEnd - iStart); 781c843016eSdrh rc = sqlite3_step(pStmt); 782c843016eSdrh if( rc!=SQLITE_DONE ) abendError("%s", sqlite3_errmsg(dataDb)); 783c843016eSdrh sqlite3_reset(pStmt); 784c843016eSdrh } 785c843016eSdrh 786b3df0c67Sdrh /* Free the SQL from the current test case 787b3df0c67Sdrh */ 7889985dabbSdrh if( zToFree ){ 7899985dabbSdrh sqlite3_free(zToFree); 7909985dabbSdrh zToFree = 0; 7919985dabbSdrh } 792f34e9aabSdrh zIn[iNext] = cSaved; 793b3df0c67Sdrh 794b3df0c67Sdrh /* Show test-case results in --verbose mode 795b3df0c67Sdrh */ 7961cbb7fa9Sdrh if( verboseFlag ){ 797268e72f9Sdrh printf("RESULT-CODE: %d\n", rc); 798268e72f9Sdrh if( zErrMsg ){ 799048810b6Sdrh printf("ERROR-MSG: [%s]\n", zErrBuf); 800268e72f9Sdrh } 8019f18f743Sdrh fflush(stdout); 8021cbb7fa9Sdrh } 803b3df0c67Sdrh 804b3df0c67Sdrh /* Simulate an error if the TEST_FAILURE environment variable is "5". 805b3df0c67Sdrh ** This is used to verify that automated test script really do spot 806b3df0c67Sdrh ** errors that occur in this test program. 807b3df0c67Sdrh */ 8088ea5eca1Sdrh if( zFailCode ){ 8098ea5eca1Sdrh if( zFailCode[0]=='5' && zFailCode[1]==0 ){ 810e1a71a58Sdrh abendError("simulated failure"); 8118ea5eca1Sdrh }else if( zFailCode[0]!=0 ){ 8128ea5eca1Sdrh /* If TEST_FAILURE is something other than 5, just exit the test 8138ea5eca1Sdrh ** early */ 8148ea5eca1Sdrh printf("\nExit early due to TEST_FAILURE being set"); 8158ea5eca1Sdrh break; 8168ea5eca1Sdrh } 817f34e9aabSdrh } 818e1a71a58Sdrh } 819f332071bSdrh if( !verboseFlag && multiTest && !quietFlag && !oomFlag ) printf("\n"); 820b3df0c67Sdrh } 821b3df0c67Sdrh 822b3df0c67Sdrh /* Report total number of tests run 823b3df0c67Sdrh */ 8241cbb7fa9Sdrh if( nTest>1 && !quietFlag ){ 8251a57c17dSdrh sqlite3_int64 iElapse = timeOfDay() - iBegin; 8261a57c17dSdrh printf("%s: 0 errors out of %d tests in %d.%03d seconds\nSQLite %s %s\n", 8271a57c17dSdrh g.zArgv0, nTest, (int)(iElapse/1000), (int)(iElapse%1000), 8281a57c17dSdrh sqlite3_libversion(), sqlite3_sourceid()); 829875bafa1Sdrh } 830b3df0c67Sdrh 831b3df0c67Sdrh /* Write the unique test cases if the --unique-cases flag was used 832b3df0c67Sdrh */ 833875bafa1Sdrh if( zDataOut ){ 834875bafa1Sdrh int n = 0; 835e1a71a58Sdrh FILE *out = fopen(zDataOut, "wb"); 836875bafa1Sdrh if( out==0 ) abendError("cannot open %s for writing", zDataOut); 837e1a71a58Sdrh if( nHeader>0 ) fwrite(zIn, nHeader, 1, out); 838875bafa1Sdrh sqlite3_finalize(pStmt); 839c843016eSdrh rc = sqlite3_prepare_v2(dataDb, "SELECT sql, tm FROM testcase ORDER BY tm, sql", 840c843016eSdrh -1, &pStmt, 0); 841875bafa1Sdrh if( rc ) abendError("%s", sqlite3_errmsg(dataDb)); 842875bafa1Sdrh while( sqlite3_step(pStmt)==SQLITE_ROW ){ 843c843016eSdrh fprintf(out,"/****<%d:%dms>****/", ++n, sqlite3_column_int(pStmt,1)); 844875bafa1Sdrh fwrite(sqlite3_column_blob(pStmt,0),sqlite3_column_bytes(pStmt,0),1,out); 845875bafa1Sdrh } 846875bafa1Sdrh fclose(out); 847875bafa1Sdrh sqlite3_finalize(pStmt); 848875bafa1Sdrh sqlite3_close(dataDb); 8491cbb7fa9Sdrh } 850b3df0c67Sdrh 851b3df0c67Sdrh /* Clean up and exit. 852b3df0c67Sdrh */ 853b3df0c67Sdrh free(azInFile); 854f34e9aabSdrh free(zIn); 8554a74d076Sdrh free(pHeap); 8564a74d076Sdrh free(pLook); 8574a74d076Sdrh free(pScratch); 8584a74d076Sdrh free(pPCache); 859f34e9aabSdrh return 0; 860268e72f9Sdrh } 861