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"
70c56fac74Sdrh #define ISDIGIT(X) isdigit((unsigned char)(X))
71268e72f9Sdrh
72268e72f9Sdrh /*
73268e72f9Sdrh ** All global variables are gathered into the "g" singleton.
74268e72f9Sdrh */
75268e72f9Sdrh struct GlobalVars {
76268e72f9Sdrh const char *zArgv0; /* Name of program */
77048810b6Sdrh sqlite3_mem_methods sOrigMem; /* Original memory methods */
78048810b6Sdrh sqlite3_mem_methods sOomMem; /* Memory methods with OOM simulator */
79048810b6Sdrh int iOomCntdown; /* Memory fails on 1 to 0 transition */
80048810b6Sdrh int nOomFault; /* Increments for each OOM fault */
81048810b6Sdrh int bOomOnce; /* Fail just once if true */
82048810b6Sdrh int bOomEnable; /* True to enable OOM simulation */
83048810b6Sdrh int nOomBrkpt; /* Number of calls to oomFault() */
840ee751fbSdrh char zTestName[100]; /* Name of current test */
85268e72f9Sdrh } g;
86268e72f9Sdrh
87048810b6Sdrh /*
88f332071bSdrh ** Maximum number of iterations for an OOM test
89f332071bSdrh */
90f332071bSdrh #ifndef OOM_MAX
917c84c02cSdrh # define OOM_MAX 625
92f332071bSdrh #endif
93f332071bSdrh
94f332071bSdrh /*
95048810b6Sdrh ** This routine is called when a simulated OOM occurs. It exists as a
96048810b6Sdrh ** convenient place to set a debugger breakpoint.
97048810b6Sdrh */
oomFault(void)98048810b6Sdrh static void oomFault(void){
99be5248f0Sdrh g.nOomBrkpt++; /* Prevent oomFault() from being optimized out */
100048810b6Sdrh }
101268e72f9Sdrh
102268e72f9Sdrh
103048810b6Sdrh /* Versions of malloc() and realloc() that simulate OOM conditions */
oomMalloc(int nByte)104048810b6Sdrh static void *oomMalloc(int nByte){
105048810b6Sdrh if( nByte>0 && g.bOomEnable && g.iOomCntdown>0 ){
106048810b6Sdrh g.iOomCntdown--;
107048810b6Sdrh if( g.iOomCntdown==0 ){
108048810b6Sdrh if( g.nOomFault==0 ) oomFault();
109048810b6Sdrh g.nOomFault++;
110048810b6Sdrh if( !g.bOomOnce ) g.iOomCntdown = 1;
111048810b6Sdrh return 0;
112048810b6Sdrh }
113048810b6Sdrh }
114048810b6Sdrh return g.sOrigMem.xMalloc(nByte);
115048810b6Sdrh }
oomRealloc(void * pOld,int nByte)116048810b6Sdrh static void *oomRealloc(void *pOld, int nByte){
117048810b6Sdrh if( nByte>0 && g.bOomEnable && g.iOomCntdown>0 ){
118048810b6Sdrh g.iOomCntdown--;
119048810b6Sdrh if( g.iOomCntdown==0 ){
120048810b6Sdrh if( g.nOomFault==0 ) oomFault();
121048810b6Sdrh g.nOomFault++;
122048810b6Sdrh if( !g.bOomOnce ) g.iOomCntdown = 1;
123048810b6Sdrh return 0;
124048810b6Sdrh }
125048810b6Sdrh }
126048810b6Sdrh return g.sOrigMem.xRealloc(pOld, nByte);
127048810b6Sdrh }
128048810b6Sdrh
129268e72f9Sdrh /*
130268e72f9Sdrh ** Print an error message and abort in such a way to indicate to the
131268e72f9Sdrh ** fuzzer that this counts as a crash.
132268e72f9Sdrh */
abendError(const char * zFormat,...)133268e72f9Sdrh static void abendError(const char *zFormat, ...){
134268e72f9Sdrh va_list ap;
135be5248f0Sdrh if( g.zTestName[0] ){
136be5248f0Sdrh fprintf(stderr, "%s (%s): ", g.zArgv0, g.zTestName);
137be5248f0Sdrh }else{
138268e72f9Sdrh fprintf(stderr, "%s: ", g.zArgv0);
139be5248f0Sdrh }
140268e72f9Sdrh va_start(ap, zFormat);
141268e72f9Sdrh vfprintf(stderr, zFormat, ap);
142268e72f9Sdrh va_end(ap);
143268e72f9Sdrh fprintf(stderr, "\n");
144268e72f9Sdrh abort();
145268e72f9Sdrh }
146268e72f9Sdrh /*
147268e72f9Sdrh ** Print an error message and quit, but not in a way that would look
148268e72f9Sdrh ** like a crash.
149268e72f9Sdrh */
fatalError(const char * zFormat,...)150268e72f9Sdrh static void fatalError(const char *zFormat, ...){
151268e72f9Sdrh va_list ap;
152be5248f0Sdrh if( g.zTestName[0] ){
153be5248f0Sdrh fprintf(stderr, "%s (%s): ", g.zArgv0, g.zTestName);
154be5248f0Sdrh }else{
155268e72f9Sdrh fprintf(stderr, "%s: ", g.zArgv0);
156be5248f0Sdrh }
157268e72f9Sdrh va_start(ap, zFormat);
158268e72f9Sdrh vfprintf(stderr, zFormat, ap);
159268e72f9Sdrh va_end(ap);
160268e72f9Sdrh fprintf(stderr, "\n");
161268e72f9Sdrh exit(1);
162268e72f9Sdrh }
163268e72f9Sdrh
164268e72f9Sdrh /*
1654a74d076Sdrh ** Evaluate some SQL. Abort if unable.
1664a74d076Sdrh */
sqlexec(sqlite3 * db,const char * zFormat,...)1674a74d076Sdrh static void sqlexec(sqlite3 *db, const char *zFormat, ...){
1684a74d076Sdrh va_list ap;
1694a74d076Sdrh char *zSql;
1704a74d076Sdrh char *zErrMsg = 0;
1714a74d076Sdrh int rc;
1724a74d076Sdrh va_start(ap, zFormat);
1734a74d076Sdrh zSql = sqlite3_vmprintf(zFormat, ap);
1744a74d076Sdrh va_end(ap);
1754a74d076Sdrh rc = sqlite3_exec(db, zSql, 0, 0, &zErrMsg);
1764a74d076Sdrh if( rc ) abendError("failed sql [%s]: %s", zSql, zErrMsg);
1774a74d076Sdrh sqlite3_free(zSql);
1784a74d076Sdrh }
1794a74d076Sdrh
1804a74d076Sdrh /*
181268e72f9Sdrh ** This callback is invoked by sqlite3_log().
182268e72f9Sdrh */
shellLog(void * pNotUsed,int iErrCode,const char * zMsg)183268e72f9Sdrh static void shellLog(void *pNotUsed, int iErrCode, const char *zMsg){
184268e72f9Sdrh printf("LOG: (%d) %s\n", iErrCode, zMsg);
1859f18f743Sdrh fflush(stdout);
186268e72f9Sdrh }
shellLogNoop(void * pNotUsed,int iErrCode,const char * zMsg)1870ee751fbSdrh static void shellLogNoop(void *pNotUsed, int iErrCode, const char *zMsg){
1880ee751fbSdrh return;
1890ee751fbSdrh }
190268e72f9Sdrh
191268e72f9Sdrh /*
192268e72f9Sdrh ** This callback is invoked by sqlite3_exec() to return query results.
193268e72f9Sdrh */
execCallback(void * NotUsed,int argc,char ** argv,char ** colv)194268e72f9Sdrh static int execCallback(void *NotUsed, int argc, char **argv, char **colv){
195268e72f9Sdrh int i;
196268e72f9Sdrh static unsigned cnt = 0;
197268e72f9Sdrh printf("ROW #%u:\n", ++cnt);
19855377b47Sdrh if( argv ){
199268e72f9Sdrh for(i=0; i<argc; i++){
200268e72f9Sdrh printf(" %s=", colv[i]);
201268e72f9Sdrh if( argv[i] ){
202268e72f9Sdrh printf("[%s]\n", argv[i]);
203268e72f9Sdrh }else{
204268e72f9Sdrh printf("NULL\n");
205268e72f9Sdrh }
206268e72f9Sdrh }
20755377b47Sdrh }
2089f18f743Sdrh fflush(stdout);
209268e72f9Sdrh return 0;
210268e72f9Sdrh }
execNoop(void * NotUsed,int argc,char ** argv,char ** colv)2111cbb7fa9Sdrh static int execNoop(void *NotUsed, int argc, char **argv, char **colv){
2121cbb7fa9Sdrh return 0;
2131cbb7fa9Sdrh }
214268e72f9Sdrh
21561a0d6bcSdrh #ifndef SQLITE_OMIT_TRACE
216268e72f9Sdrh /*
217268e72f9Sdrh ** This callback is invoked by sqlite3_trace() as each SQL statement
218268e72f9Sdrh ** starts.
219268e72f9Sdrh */
traceCallback(void * NotUsed,const char * zMsg)220268e72f9Sdrh static void traceCallback(void *NotUsed, const char *zMsg){
221268e72f9Sdrh printf("TRACE: %s\n", zMsg);
2229f18f743Sdrh fflush(stdout);
223268e72f9Sdrh }
traceNoop(void * NotUsed,const char * zMsg)2240ee751fbSdrh static void traceNoop(void *NotUsed, const char *zMsg){
2250ee751fbSdrh return;
2260ee751fbSdrh }
22761a0d6bcSdrh #endif
228268e72f9Sdrh
229268e72f9Sdrh /***************************************************************************
2306918e2f9Sdrh ** String accumulator object
2316918e2f9Sdrh */
2326918e2f9Sdrh typedef struct Str Str;
2336918e2f9Sdrh struct Str {
2346918e2f9Sdrh char *z; /* The string. Memory from malloc() */
2356918e2f9Sdrh sqlite3_uint64 n; /* Bytes of input used */
2366918e2f9Sdrh sqlite3_uint64 nAlloc; /* Bytes allocated to z[] */
2376918e2f9Sdrh int oomErr; /* OOM error has been seen */
2386918e2f9Sdrh };
2396918e2f9Sdrh
2406918e2f9Sdrh /* Initialize a Str object */
StrInit(Str * p)2416918e2f9Sdrh static void StrInit(Str *p){
2426918e2f9Sdrh memset(p, 0, sizeof(*p));
2436918e2f9Sdrh }
2446918e2f9Sdrh
2456918e2f9Sdrh /* Append text to the end of a Str object */
StrAppend(Str * p,const char * z)2466918e2f9Sdrh static void StrAppend(Str *p, const char *z){
2476918e2f9Sdrh sqlite3_uint64 n = strlen(z);
2486918e2f9Sdrh if( p->n + n >= p->nAlloc ){
2496918e2f9Sdrh char *zNew;
2506918e2f9Sdrh sqlite3_uint64 nNew;
2516918e2f9Sdrh if( p->oomErr ) return;
2526918e2f9Sdrh nNew = p->nAlloc*2 + 100 + n;
253*b1ed717fSmistachkin zNew = sqlite3_realloc(p->z, (int)nNew);
2546918e2f9Sdrh if( zNew==0 ){
2556918e2f9Sdrh sqlite3_free(p->z);
2566918e2f9Sdrh memset(p, 0, sizeof(*p));
2576918e2f9Sdrh p->oomErr = 1;
2586918e2f9Sdrh return;
2596918e2f9Sdrh }
2606918e2f9Sdrh p->z = zNew;
2616918e2f9Sdrh p->nAlloc = nNew;
2626918e2f9Sdrh }
263*b1ed717fSmistachkin memcpy(p->z + p->n, z, (size_t)n);
2646918e2f9Sdrh p->n += n;
2656918e2f9Sdrh p->z[p->n] = 0;
2666918e2f9Sdrh }
2676918e2f9Sdrh
2686918e2f9Sdrh /* Return the current string content */
StrStr(Str * p)2696918e2f9Sdrh static char *StrStr(Str *p){
2706918e2f9Sdrh return p->z;
2716918e2f9Sdrh }
2726918e2f9Sdrh
2736918e2f9Sdrh /* Free the string */
StrFree(Str * p)2746918e2f9Sdrh static void StrFree(Str *p){
2756918e2f9Sdrh sqlite3_free(p->z);
2766918e2f9Sdrh StrInit(p);
2776918e2f9Sdrh }
2786918e2f9Sdrh
2796918e2f9Sdrh /***************************************************************************
280268e72f9Sdrh ** eval() implementation copied from ../ext/misc/eval.c
281268e72f9Sdrh */
282268e72f9Sdrh /*
283268e72f9Sdrh ** Structure used to accumulate the output
284268e72f9Sdrh */
285268e72f9Sdrh struct EvalResult {
286268e72f9Sdrh char *z; /* Accumulated output */
287268e72f9Sdrh const char *zSep; /* Separator */
288268e72f9Sdrh int szSep; /* Size of the separator string */
289268e72f9Sdrh sqlite3_int64 nAlloc; /* Number of bytes allocated for z[] */
290268e72f9Sdrh sqlite3_int64 nUsed; /* Number of bytes of z[] actually used */
291268e72f9Sdrh };
292268e72f9Sdrh
293268e72f9Sdrh /*
294268e72f9Sdrh ** Callback from sqlite_exec() for the eval() function.
295268e72f9Sdrh */
callback(void * pCtx,int argc,char ** argv,char ** colnames)296268e72f9Sdrh static int callback(void *pCtx, int argc, char **argv, char **colnames){
297268e72f9Sdrh struct EvalResult *p = (struct EvalResult*)pCtx;
298268e72f9Sdrh int i;
299268e72f9Sdrh for(i=0; i<argc; i++){
300268e72f9Sdrh const char *z = argv[i] ? argv[i] : "";
301268e72f9Sdrh size_t sz = strlen(z);
302268e72f9Sdrh if( (sqlite3_int64)sz+p->nUsed+p->szSep+1 > p->nAlloc ){
303268e72f9Sdrh char *zNew;
304268e72f9Sdrh p->nAlloc = p->nAlloc*2 + sz + p->szSep + 1;
305268e72f9Sdrh /* Using sqlite3_realloc64() would be better, but it is a recent
306268e72f9Sdrh ** addition and will cause a segfault if loaded by an older version
307268e72f9Sdrh ** of SQLite. */
308268e72f9Sdrh zNew = p->nAlloc<=0x7fffffff ? sqlite3_realloc(p->z, (int)p->nAlloc) : 0;
309268e72f9Sdrh if( zNew==0 ){
310268e72f9Sdrh sqlite3_free(p->z);
311268e72f9Sdrh memset(p, 0, sizeof(*p));
312268e72f9Sdrh return 1;
313268e72f9Sdrh }
314268e72f9Sdrh p->z = zNew;
315268e72f9Sdrh }
316268e72f9Sdrh if( p->nUsed>0 ){
317268e72f9Sdrh memcpy(&p->z[p->nUsed], p->zSep, p->szSep);
318268e72f9Sdrh p->nUsed += p->szSep;
319268e72f9Sdrh }
320268e72f9Sdrh memcpy(&p->z[p->nUsed], z, sz);
321268e72f9Sdrh p->nUsed += sz;
322268e72f9Sdrh }
323268e72f9Sdrh return 0;
324268e72f9Sdrh }
325268e72f9Sdrh
326268e72f9Sdrh /*
327268e72f9Sdrh ** Implementation of the eval(X) and eval(X,Y) SQL functions.
328268e72f9Sdrh **
329268e72f9Sdrh ** Evaluate the SQL text in X. Return the results, using string
330268e72f9Sdrh ** Y as the separator. If Y is omitted, use a single space character.
331268e72f9Sdrh */
sqlEvalFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)332268e72f9Sdrh static void sqlEvalFunc(
333268e72f9Sdrh sqlite3_context *context,
334268e72f9Sdrh int argc,
335268e72f9Sdrh sqlite3_value **argv
336268e72f9Sdrh ){
337268e72f9Sdrh const char *zSql;
338268e72f9Sdrh sqlite3 *db;
339268e72f9Sdrh char *zErr = 0;
340268e72f9Sdrh int rc;
341268e72f9Sdrh struct EvalResult x;
342268e72f9Sdrh
343268e72f9Sdrh memset(&x, 0, sizeof(x));
344268e72f9Sdrh x.zSep = " ";
345268e72f9Sdrh zSql = (const char*)sqlite3_value_text(argv[0]);
346268e72f9Sdrh if( zSql==0 ) return;
347268e72f9Sdrh if( argc>1 ){
348268e72f9Sdrh x.zSep = (const char*)sqlite3_value_text(argv[1]);
349268e72f9Sdrh if( x.zSep==0 ) return;
350268e72f9Sdrh }
351268e72f9Sdrh x.szSep = (int)strlen(x.zSep);
352268e72f9Sdrh db = sqlite3_context_db_handle(context);
353268e72f9Sdrh rc = sqlite3_exec(db, zSql, callback, &x, &zErr);
354268e72f9Sdrh if( rc!=SQLITE_OK ){
355268e72f9Sdrh sqlite3_result_error(context, zErr, -1);
356268e72f9Sdrh sqlite3_free(zErr);
357268e72f9Sdrh }else if( x.zSep==0 ){
358268e72f9Sdrh sqlite3_result_error_nomem(context);
359268e72f9Sdrh sqlite3_free(x.z);
360268e72f9Sdrh }else{
361268e72f9Sdrh sqlite3_result_text(context, x.z, (int)x.nUsed, sqlite3_free);
362268e72f9Sdrh }
363268e72f9Sdrh }
364268e72f9Sdrh /* End of the eval() implementation
365268e72f9Sdrh ******************************************************************************/
366268e72f9Sdrh
3679f6dd025Sdrh /******************************************************************************
3689f6dd025Sdrh ** The generate_series(START,END,STEP) eponymous table-valued function.
3699f6dd025Sdrh **
3709f6dd025Sdrh ** This code is copy/pasted from ext/misc/series.c in the SQLite source tree.
3719f6dd025Sdrh */
3729f6dd025Sdrh /* series_cursor is a subclass of sqlite3_vtab_cursor which will
3739f6dd025Sdrh ** serve as the underlying representation of a cursor that scans
3749f6dd025Sdrh ** over rows of the result
3759f6dd025Sdrh */
3769f6dd025Sdrh typedef struct series_cursor series_cursor;
3779f6dd025Sdrh struct series_cursor {
3789f6dd025Sdrh sqlite3_vtab_cursor base; /* Base class - must be first */
3799f6dd025Sdrh int isDesc; /* True to count down rather than up */
3809f6dd025Sdrh sqlite3_int64 iRowid; /* The rowid */
3819f6dd025Sdrh sqlite3_int64 iValue; /* Current value ("value") */
3829f6dd025Sdrh sqlite3_int64 mnValue; /* Mimimum value ("start") */
3839f6dd025Sdrh sqlite3_int64 mxValue; /* Maximum value ("stop") */
3849f6dd025Sdrh sqlite3_int64 iStep; /* Increment ("step") */
3859f6dd025Sdrh };
3869f6dd025Sdrh
3879f6dd025Sdrh /*
3889f6dd025Sdrh ** The seriesConnect() method is invoked to create a new
3899f6dd025Sdrh ** series_vtab that describes the generate_series virtual table.
3909f6dd025Sdrh **
3919f6dd025Sdrh ** Think of this routine as the constructor for series_vtab objects.
3929f6dd025Sdrh **
3939f6dd025Sdrh ** All this routine needs to do is:
3949f6dd025Sdrh **
3959f6dd025Sdrh ** (1) Allocate the series_vtab object and initialize all fields.
3969f6dd025Sdrh **
3979f6dd025Sdrh ** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the
3989f6dd025Sdrh ** result set of queries against generate_series will look like.
3999f6dd025Sdrh */
seriesConnect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)4009f6dd025Sdrh static int seriesConnect(
4019f6dd025Sdrh sqlite3 *db,
4029f6dd025Sdrh void *pAux,
4039f6dd025Sdrh int argc, const char *const*argv,
4049f6dd025Sdrh sqlite3_vtab **ppVtab,
4059f6dd025Sdrh char **pzErr
4069f6dd025Sdrh ){
4079f6dd025Sdrh sqlite3_vtab *pNew;
4089f6dd025Sdrh int rc;
4099f6dd025Sdrh
4109f6dd025Sdrh /* Column numbers */
4119f6dd025Sdrh #define SERIES_COLUMN_VALUE 0
4129f6dd025Sdrh #define SERIES_COLUMN_START 1
4139f6dd025Sdrh #define SERIES_COLUMN_STOP 2
4149f6dd025Sdrh #define SERIES_COLUMN_STEP 3
4159f6dd025Sdrh
4169f6dd025Sdrh rc = sqlite3_declare_vtab(db,
4179f6dd025Sdrh "CREATE TABLE x(value,start hidden,stop hidden,step hidden)");
4189f6dd025Sdrh if( rc==SQLITE_OK ){
4199f6dd025Sdrh pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
4209f6dd025Sdrh if( pNew==0 ) return SQLITE_NOMEM;
4219f6dd025Sdrh memset(pNew, 0, sizeof(*pNew));
4229f6dd025Sdrh }
4239f6dd025Sdrh return rc;
4249f6dd025Sdrh }
4259f6dd025Sdrh
4269f6dd025Sdrh /*
4279f6dd025Sdrh ** This method is the destructor for series_cursor objects.
4289f6dd025Sdrh */
seriesDisconnect(sqlite3_vtab * pVtab)4299f6dd025Sdrh static int seriesDisconnect(sqlite3_vtab *pVtab){
4309f6dd025Sdrh sqlite3_free(pVtab);
4319f6dd025Sdrh return SQLITE_OK;
4329f6dd025Sdrh }
4339f6dd025Sdrh
4349f6dd025Sdrh /*
4359f6dd025Sdrh ** Constructor for a new series_cursor object.
4369f6dd025Sdrh */
seriesOpen(sqlite3_vtab * p,sqlite3_vtab_cursor ** ppCursor)4379f6dd025Sdrh static int seriesOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
4389f6dd025Sdrh series_cursor *pCur;
4399f6dd025Sdrh pCur = sqlite3_malloc( sizeof(*pCur) );
4409f6dd025Sdrh if( pCur==0 ) return SQLITE_NOMEM;
4419f6dd025Sdrh memset(pCur, 0, sizeof(*pCur));
4429f6dd025Sdrh *ppCursor = &pCur->base;
4439f6dd025Sdrh return SQLITE_OK;
4449f6dd025Sdrh }
4459f6dd025Sdrh
4469f6dd025Sdrh /*
4479f6dd025Sdrh ** Destructor for a series_cursor.
4489f6dd025Sdrh */
seriesClose(sqlite3_vtab_cursor * cur)4499f6dd025Sdrh static int seriesClose(sqlite3_vtab_cursor *cur){
4509f6dd025Sdrh sqlite3_free(cur);
4519f6dd025Sdrh return SQLITE_OK;
4529f6dd025Sdrh }
4539f6dd025Sdrh
4549f6dd025Sdrh
4559f6dd025Sdrh /*
4569f6dd025Sdrh ** Advance a series_cursor to its next row of output.
4579f6dd025Sdrh */
seriesNext(sqlite3_vtab_cursor * cur)4589f6dd025Sdrh static int seriesNext(sqlite3_vtab_cursor *cur){
4599f6dd025Sdrh series_cursor *pCur = (series_cursor*)cur;
4609f6dd025Sdrh if( pCur->isDesc ){
4619f6dd025Sdrh pCur->iValue -= pCur->iStep;
4629f6dd025Sdrh }else{
4639f6dd025Sdrh pCur->iValue += pCur->iStep;
4649f6dd025Sdrh }
4659f6dd025Sdrh pCur->iRowid++;
4669f6dd025Sdrh return SQLITE_OK;
4679f6dd025Sdrh }
4689f6dd025Sdrh
4699f6dd025Sdrh /*
4709f6dd025Sdrh ** Return values of columns for the row at which the series_cursor
4719f6dd025Sdrh ** is currently pointing.
4729f6dd025Sdrh */
seriesColumn(sqlite3_vtab_cursor * cur,sqlite3_context * ctx,int i)4739f6dd025Sdrh static int seriesColumn(
4749f6dd025Sdrh sqlite3_vtab_cursor *cur, /* The cursor */
4759f6dd025Sdrh sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
4769f6dd025Sdrh int i /* Which column to return */
4779f6dd025Sdrh ){
4789f6dd025Sdrh series_cursor *pCur = (series_cursor*)cur;
4799f6dd025Sdrh sqlite3_int64 x = 0;
4809f6dd025Sdrh switch( i ){
4819f6dd025Sdrh case SERIES_COLUMN_START: x = pCur->mnValue; break;
4829f6dd025Sdrh case SERIES_COLUMN_STOP: x = pCur->mxValue; break;
4839f6dd025Sdrh case SERIES_COLUMN_STEP: x = pCur->iStep; break;
4849f6dd025Sdrh default: x = pCur->iValue; break;
4859f6dd025Sdrh }
4869f6dd025Sdrh sqlite3_result_int64(ctx, x);
4879f6dd025Sdrh return SQLITE_OK;
4889f6dd025Sdrh }
4899f6dd025Sdrh
4909f6dd025Sdrh /*
4919f6dd025Sdrh ** Return the rowid for the current row. In this implementation, the
4929f6dd025Sdrh ** rowid is the same as the output value.
4939f6dd025Sdrh */
seriesRowid(sqlite3_vtab_cursor * cur,sqlite_int64 * pRowid)4949f6dd025Sdrh static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
4959f6dd025Sdrh series_cursor *pCur = (series_cursor*)cur;
4969f6dd025Sdrh *pRowid = pCur->iRowid;
4979f6dd025Sdrh return SQLITE_OK;
4989f6dd025Sdrh }
4999f6dd025Sdrh
5009f6dd025Sdrh /*
5019f6dd025Sdrh ** Return TRUE if the cursor has been moved off of the last
5029f6dd025Sdrh ** row of output.
5039f6dd025Sdrh */
seriesEof(sqlite3_vtab_cursor * cur)5049f6dd025Sdrh static int seriesEof(sqlite3_vtab_cursor *cur){
5059f6dd025Sdrh series_cursor *pCur = (series_cursor*)cur;
5069f6dd025Sdrh if( pCur->isDesc ){
5079f6dd025Sdrh return pCur->iValue < pCur->mnValue;
5089f6dd025Sdrh }else{
5099f6dd025Sdrh return pCur->iValue > pCur->mxValue;
5109f6dd025Sdrh }
5119f6dd025Sdrh }
5129f6dd025Sdrh
5139f6dd025Sdrh /* True to cause run-time checking of the start=, stop=, and/or step=
5149f6dd025Sdrh ** parameters. The only reason to do this is for testing the
5159f6dd025Sdrh ** constraint checking logic for virtual tables in the SQLite core.
5169f6dd025Sdrh */
5179f6dd025Sdrh #ifndef SQLITE_SERIES_CONSTRAINT_VERIFY
5189f6dd025Sdrh # define SQLITE_SERIES_CONSTRAINT_VERIFY 0
5199f6dd025Sdrh #endif
5209f6dd025Sdrh
5219f6dd025Sdrh /*
5229f6dd025Sdrh ** This method is called to "rewind" the series_cursor object back
5239f6dd025Sdrh ** to the first row of output. This method is always called at least
5249f6dd025Sdrh ** once prior to any call to seriesColumn() or seriesRowid() or
5259f6dd025Sdrh ** seriesEof().
5269f6dd025Sdrh **
5279f6dd025Sdrh ** The query plan selected by seriesBestIndex is passed in the idxNum
5289f6dd025Sdrh ** parameter. (idxStr is not used in this implementation.) idxNum
5299f6dd025Sdrh ** is a bitmask showing which constraints are available:
5309f6dd025Sdrh **
5319f6dd025Sdrh ** 1: start=VALUE
5329f6dd025Sdrh ** 2: stop=VALUE
5339f6dd025Sdrh ** 4: step=VALUE
5349f6dd025Sdrh **
5359f6dd025Sdrh ** Also, if bit 8 is set, that means that the series should be output
5369f6dd025Sdrh ** in descending order rather than in ascending order.
5379f6dd025Sdrh **
5389f6dd025Sdrh ** This routine should initialize the cursor and position it so that it
5399f6dd025Sdrh ** is pointing at the first row, or pointing off the end of the table
5409f6dd025Sdrh ** (so that seriesEof() will return true) if the table is empty.
5419f6dd025Sdrh */
seriesFilter(sqlite3_vtab_cursor * pVtabCursor,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)5429f6dd025Sdrh static int seriesFilter(
5439f6dd025Sdrh sqlite3_vtab_cursor *pVtabCursor,
5449f6dd025Sdrh int idxNum, const char *idxStr,
5459f6dd025Sdrh int argc, sqlite3_value **argv
5469f6dd025Sdrh ){
5479f6dd025Sdrh series_cursor *pCur = (series_cursor *)pVtabCursor;
5489f6dd025Sdrh int i = 0;
5499f6dd025Sdrh if( idxNum & 1 ){
5509f6dd025Sdrh pCur->mnValue = sqlite3_value_int64(argv[i++]);
5519f6dd025Sdrh }else{
5529f6dd025Sdrh pCur->mnValue = 0;
5539f6dd025Sdrh }
5549f6dd025Sdrh if( idxNum & 2 ){
5559f6dd025Sdrh pCur->mxValue = sqlite3_value_int64(argv[i++]);
5569f6dd025Sdrh }else{
5579f6dd025Sdrh pCur->mxValue = 0xffffffff;
5589f6dd025Sdrh }
5599f6dd025Sdrh if( idxNum & 4 ){
5609f6dd025Sdrh pCur->iStep = sqlite3_value_int64(argv[i++]);
5619f6dd025Sdrh if( pCur->iStep<1 ) pCur->iStep = 1;
5629f6dd025Sdrh }else{
5639f6dd025Sdrh pCur->iStep = 1;
5649f6dd025Sdrh }
5659f6dd025Sdrh if( idxNum & 8 ){
5669f6dd025Sdrh pCur->isDesc = 1;
5679f6dd025Sdrh pCur->iValue = pCur->mxValue;
5689f6dd025Sdrh if( pCur->iStep>0 ){
5699f6dd025Sdrh pCur->iValue -= (pCur->mxValue - pCur->mnValue)%pCur->iStep;
5709f6dd025Sdrh }
5719f6dd025Sdrh }else{
5729f6dd025Sdrh pCur->isDesc = 0;
5739f6dd025Sdrh pCur->iValue = pCur->mnValue;
5749f6dd025Sdrh }
5759f6dd025Sdrh pCur->iRowid = 1;
5769f6dd025Sdrh return SQLITE_OK;
5779f6dd025Sdrh }
5789f6dd025Sdrh
5799f6dd025Sdrh /*
5809f6dd025Sdrh ** SQLite will invoke this method one or more times while planning a query
5819f6dd025Sdrh ** that uses the generate_series virtual table. This routine needs to create
5829f6dd025Sdrh ** a query plan for each invocation and compute an estimated cost for that
5839f6dd025Sdrh ** plan.
5849f6dd025Sdrh **
5859f6dd025Sdrh ** In this implementation idxNum is used to represent the
5869f6dd025Sdrh ** query plan. idxStr is unused.
5879f6dd025Sdrh **
5889f6dd025Sdrh ** The query plan is represented by bits in idxNum:
5899f6dd025Sdrh **
5909f6dd025Sdrh ** (1) start = $value -- constraint exists
5919f6dd025Sdrh ** (2) stop = $value -- constraint exists
5929f6dd025Sdrh ** (4) step = $value -- constraint exists
5939f6dd025Sdrh ** (8) output in descending order
5949f6dd025Sdrh */
seriesBestIndex(sqlite3_vtab * tab,sqlite3_index_info * pIdxInfo)5959f6dd025Sdrh static int seriesBestIndex(
5969f6dd025Sdrh sqlite3_vtab *tab,
5979f6dd025Sdrh sqlite3_index_info *pIdxInfo
5989f6dd025Sdrh ){
5999f6dd025Sdrh int i; /* Loop over constraints */
6009f6dd025Sdrh int idxNum = 0; /* The query plan bitmask */
6019f6dd025Sdrh int startIdx = -1; /* Index of the start= constraint, or -1 if none */
6029f6dd025Sdrh int stopIdx = -1; /* Index of the stop= constraint, or -1 if none */
6039f6dd025Sdrh int stepIdx = -1; /* Index of the step= constraint, or -1 if none */
6049f6dd025Sdrh int nArg = 0; /* Number of arguments that seriesFilter() expects */
6059f6dd025Sdrh
6069f6dd025Sdrh const struct sqlite3_index_constraint *pConstraint;
6079f6dd025Sdrh pConstraint = pIdxInfo->aConstraint;
6089f6dd025Sdrh for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
6099f6dd025Sdrh if( pConstraint->usable==0 ) continue;
6109f6dd025Sdrh if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue;
6119f6dd025Sdrh switch( pConstraint->iColumn ){
6129f6dd025Sdrh case SERIES_COLUMN_START:
6139f6dd025Sdrh startIdx = i;
6149f6dd025Sdrh idxNum |= 1;
6159f6dd025Sdrh break;
6169f6dd025Sdrh case SERIES_COLUMN_STOP:
6179f6dd025Sdrh stopIdx = i;
6189f6dd025Sdrh idxNum |= 2;
6199f6dd025Sdrh break;
6209f6dd025Sdrh case SERIES_COLUMN_STEP:
6219f6dd025Sdrh stepIdx = i;
6229f6dd025Sdrh idxNum |= 4;
6239f6dd025Sdrh break;
6249f6dd025Sdrh }
6259f6dd025Sdrh }
6269f6dd025Sdrh if( startIdx>=0 ){
6279f6dd025Sdrh pIdxInfo->aConstraintUsage[startIdx].argvIndex = ++nArg;
6289f6dd025Sdrh pIdxInfo->aConstraintUsage[startIdx].omit= !SQLITE_SERIES_CONSTRAINT_VERIFY;
6299f6dd025Sdrh }
6309f6dd025Sdrh if( stopIdx>=0 ){
6319f6dd025Sdrh pIdxInfo->aConstraintUsage[stopIdx].argvIndex = ++nArg;
6329f6dd025Sdrh pIdxInfo->aConstraintUsage[stopIdx].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY;
6339f6dd025Sdrh }
6349f6dd025Sdrh if( stepIdx>=0 ){
6359f6dd025Sdrh pIdxInfo->aConstraintUsage[stepIdx].argvIndex = ++nArg;
6369f6dd025Sdrh pIdxInfo->aConstraintUsage[stepIdx].omit = !SQLITE_SERIES_CONSTRAINT_VERIFY;
6379f6dd025Sdrh }
6389f6dd025Sdrh if( (idxNum & 3)==3 ){
6399f6dd025Sdrh /* Both start= and stop= boundaries are available. This is the
6409f6dd025Sdrh ** the preferred case */
6419f6dd025Sdrh pIdxInfo->estimatedCost = (double)(2 - ((idxNum&4)!=0));
6429f6dd025Sdrh pIdxInfo->estimatedRows = 1000;
6439f6dd025Sdrh if( pIdxInfo->nOrderBy==1 ){
6449f6dd025Sdrh if( pIdxInfo->aOrderBy[0].desc ) idxNum |= 8;
6459f6dd025Sdrh pIdxInfo->orderByConsumed = 1;
6469f6dd025Sdrh }
6479f6dd025Sdrh }else{
6489f6dd025Sdrh /* If either boundary is missing, we have to generate a huge span
6499f6dd025Sdrh ** of numbers. Make this case very expensive so that the query
6509f6dd025Sdrh ** planner will work hard to avoid it. */
6519f6dd025Sdrh pIdxInfo->estimatedCost = (double)2147483647;
6529f6dd025Sdrh pIdxInfo->estimatedRows = 2147483647;
6539f6dd025Sdrh }
6549f6dd025Sdrh pIdxInfo->idxNum = idxNum;
6559f6dd025Sdrh return SQLITE_OK;
6569f6dd025Sdrh }
6579f6dd025Sdrh
6589f6dd025Sdrh /*
6599f6dd025Sdrh ** This following structure defines all the methods for the
6609f6dd025Sdrh ** generate_series virtual table.
6619f6dd025Sdrh */
6629f6dd025Sdrh static sqlite3_module seriesModule = {
6639f6dd025Sdrh 0, /* iVersion */
6649f6dd025Sdrh 0, /* xCreate */
6659f6dd025Sdrh seriesConnect, /* xConnect */
6669f6dd025Sdrh seriesBestIndex, /* xBestIndex */
6679f6dd025Sdrh seriesDisconnect, /* xDisconnect */
6689f6dd025Sdrh 0, /* xDestroy */
6699f6dd025Sdrh seriesOpen, /* xOpen - open a cursor */
6709f6dd025Sdrh seriesClose, /* xClose - close a cursor */
6719f6dd025Sdrh seriesFilter, /* xFilter - configure scan constraints */
6729f6dd025Sdrh seriesNext, /* xNext - advance a cursor */
6739f6dd025Sdrh seriesEof, /* xEof - check for end of scan */
6749f6dd025Sdrh seriesColumn, /* xColumn - read data */
6759f6dd025Sdrh seriesRowid, /* xRowid - read data */
6769f6dd025Sdrh 0, /* xUpdate */
6779f6dd025Sdrh 0, /* xBegin */
6789f6dd025Sdrh 0, /* xSync */
6799f6dd025Sdrh 0, /* xCommit */
6809f6dd025Sdrh 0, /* xRollback */
6819f6dd025Sdrh 0, /* xFindMethod */
6829f6dd025Sdrh 0, /* xRename */
6839f6dd025Sdrh };
6849f6dd025Sdrh /* END the generate_series(START,END,STEP) implementation
6859f6dd025Sdrh *********************************************************************************/
6869f6dd025Sdrh
687268e72f9Sdrh /*
688268e72f9Sdrh ** Print sketchy documentation for this utility program
689268e72f9Sdrh */
showHelp(void)690268e72f9Sdrh static void showHelp(void){
691b3df0c67Sdrh printf("Usage: %s [options] ?FILE...?\n", g.zArgv0);
692268e72f9Sdrh printf(
693b3df0c67Sdrh "Read SQL text from FILE... (or from standard input if FILE... is omitted)\n"
694b3df0c67Sdrh "and then evaluate each block of SQL contained therein.\n"
695268e72f9Sdrh "Options:\n"
6964a74d076Sdrh " --autovacuum Enable AUTOVACUUM mode\n"
697acd33745Sdrh " --database FILE Use database FILE instead of an in-memory database\n"
698b97ad029Sdrh " --disable-lookaside Turn off lookaside memory\n"
6994a74d076Sdrh " --heap SZ MIN Memory allocator uses SZ bytes & min allocation MIN\n"
700268e72f9Sdrh " --help Show this help text\n"
7014a74d076Sdrh " --lookaside N SZ Configure lookaside for N slots of SZ bytes each\n"
702048810b6Sdrh " --oom Run each test multiple times in a simulated OOM loop\n"
7034a74d076Sdrh " --pagesize N Set the page size to N\n"
7044a74d076Sdrh " --pcache N SZ Configure N pages of pagecache each of size SZ bytes\n"
7051cbb7fa9Sdrh " -q Reduced output\n"
7061cbb7fa9Sdrh " --quiet Reduced output\n"
7074a74d076Sdrh " --scratch N SZ Configure scratch memory for N slots of SZ bytes each\n"
708875bafa1Sdrh " --unique-cases FILE Write all unique test cases to FILE\n"
7094a74d076Sdrh " --utf16be Set text encoding to UTF-16BE\n"
7104a74d076Sdrh " --utf16le Set text encoding to UTF-16LE\n"
7111cbb7fa9Sdrh " -v Increased output\n"
7121cbb7fa9Sdrh " --verbose Increased output\n"
713268e72f9Sdrh );
714268e72f9Sdrh }
715268e72f9Sdrh
7164a74d076Sdrh /*
7174a74d076Sdrh ** Return the value of a hexadecimal digit. Return -1 if the input
7184a74d076Sdrh ** is not a hex digit.
7194a74d076Sdrh */
hexDigitValue(char c)7204a74d076Sdrh static int hexDigitValue(char c){
7214a74d076Sdrh if( c>='0' && c<='9' ) return c - '0';
7224a74d076Sdrh if( c>='a' && c<='f' ) return c - 'a' + 10;
7234a74d076Sdrh if( c>='A' && c<='F' ) return c - 'A' + 10;
7244a74d076Sdrh return -1;
7254a74d076Sdrh }
7264a74d076Sdrh
7274a74d076Sdrh /*
7284a74d076Sdrh ** Interpret zArg as an integer value, possibly with suffixes.
7294a74d076Sdrh */
integerValue(const char * zArg)7304a74d076Sdrh static int integerValue(const char *zArg){
7314a74d076Sdrh sqlite3_int64 v = 0;
7324a74d076Sdrh static const struct { char *zSuffix; int iMult; } aMult[] = {
7334a74d076Sdrh { "KiB", 1024 },
7344a74d076Sdrh { "MiB", 1024*1024 },
7354a74d076Sdrh { "GiB", 1024*1024*1024 },
7364a74d076Sdrh { "KB", 1000 },
7374a74d076Sdrh { "MB", 1000000 },
7384a74d076Sdrh { "GB", 1000000000 },
7394a74d076Sdrh { "K", 1000 },
7404a74d076Sdrh { "M", 1000000 },
7414a74d076Sdrh { "G", 1000000000 },
7424a74d076Sdrh };
7434a74d076Sdrh int i;
7444a74d076Sdrh int isNeg = 0;
7454a74d076Sdrh if( zArg[0]=='-' ){
7464a74d076Sdrh isNeg = 1;
7474a74d076Sdrh zArg++;
7484a74d076Sdrh }else if( zArg[0]=='+' ){
7494a74d076Sdrh zArg++;
7504a74d076Sdrh }
7514a74d076Sdrh if( zArg[0]=='0' && zArg[1]=='x' ){
7524a74d076Sdrh int x;
7534a74d076Sdrh zArg += 2;
7544a74d076Sdrh while( (x = hexDigitValue(zArg[0]))>=0 ){
7554a74d076Sdrh v = (v<<4) + x;
7564a74d076Sdrh zArg++;
7574a74d076Sdrh }
7584a74d076Sdrh }else{
759c56fac74Sdrh while( ISDIGIT(zArg[0]) ){
7604a74d076Sdrh v = v*10 + zArg[0] - '0';
7614a74d076Sdrh zArg++;
7624a74d076Sdrh }
7634a74d076Sdrh }
7644a74d076Sdrh for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){
7654a74d076Sdrh if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
7664a74d076Sdrh v *= aMult[i].iMult;
7674a74d076Sdrh break;
7684a74d076Sdrh }
7694a74d076Sdrh }
7704a74d076Sdrh if( v>0x7fffffff ) abendError("parameter too large - max 2147483648");
7714a74d076Sdrh return (int)(isNeg? -v : v);
7724a74d076Sdrh }
7734a74d076Sdrh
774c843016eSdrh /* Return the current wall-clock time */
timeOfDay(void)775c843016eSdrh static sqlite3_int64 timeOfDay(void){
776c843016eSdrh static sqlite3_vfs *clockVfs = 0;
777c843016eSdrh sqlite3_int64 t;
778c843016eSdrh if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
779c843016eSdrh if( clockVfs->iVersion>=1 && clockVfs->xCurrentTimeInt64!=0 ){
780c843016eSdrh clockVfs->xCurrentTimeInt64(clockVfs, &t);
781c843016eSdrh }else{
782c843016eSdrh double r;
783c843016eSdrh clockVfs->xCurrentTime(clockVfs, &r);
784c843016eSdrh t = (sqlite3_int64)(r*86400000.0);
785c843016eSdrh }
786c843016eSdrh return t;
787c843016eSdrh }
788268e72f9Sdrh
main(int argc,char ** argv)789268e72f9Sdrh int main(int argc, char **argv){
790268e72f9Sdrh char *zIn = 0; /* Input text */
791268e72f9Sdrh int nAlloc = 0; /* Number of bytes allocated for zIn[] */
792268e72f9Sdrh int nIn = 0; /* Number of bytes of zIn[] used */
793268e72f9Sdrh size_t got; /* Bytes read from input */
794268e72f9Sdrh int rc = SQLITE_OK; /* Result codes from API functions */
795268e72f9Sdrh int i; /* Loop counter */
796f34e9aabSdrh int iNext; /* Next block of SQL */
797268e72f9Sdrh sqlite3 *db; /* Open database */
798268e72f9Sdrh char *zErrMsg = 0; /* Error message returned from sqlite3_exec() */
7994a74d076Sdrh const char *zEncoding = 0; /* --utf16be or --utf16le */
8004a74d076Sdrh int nHeap = 0, mnHeap = 0; /* Heap size from --heap */
8014a74d076Sdrh int nLook = 0, szLook = 0; /* --lookaside configuration */
8024a74d076Sdrh int nPCache = 0, szPCache = 0;/* --pcache configuration */
8034a74d076Sdrh int nScratch = 0, szScratch=0;/* --scratch configuration */
8044a74d076Sdrh int pageSize = 0; /* Desired page size. 0 means default */
8054a74d076Sdrh void *pHeap = 0; /* Allocated heap space */
8064a74d076Sdrh void *pLook = 0; /* Allocated lookaside space */
8074a74d076Sdrh void *pPCache = 0; /* Allocated storage for pcache */
8084a74d076Sdrh void *pScratch = 0; /* Allocated storage for scratch */
8094a74d076Sdrh int doAutovac = 0; /* True for --autovacuum */
8109985dabbSdrh char *zSql; /* SQL to run */
8119985dabbSdrh char *zToFree = 0; /* Call sqlite3_free() on this afte running zSql */
8121cbb7fa9Sdrh int verboseFlag = 0; /* --verbose or -v flag */
8131cbb7fa9Sdrh int quietFlag = 0; /* --quiet or -q flag */
8141cbb7fa9Sdrh int nTest = 0; /* Number of test cases run */
8151cbb7fa9Sdrh int multiTest = 0; /* True if there will be multiple test cases */
8161cbb7fa9Sdrh int lastPct = -1; /* Previous percentage done output */
817875bafa1Sdrh sqlite3 *dataDb = 0; /* Database holding compacted input data */
818875bafa1Sdrh sqlite3_stmt *pStmt = 0; /* Statement to insert testcase into dataDb */
819875bafa1Sdrh const char *zDataOut = 0; /* Write compacted data to this output file */
820e1a71a58Sdrh int nHeader = 0; /* Bytes of header comment text on input file */
821048810b6Sdrh int oomFlag = 0; /* --oom */
822048810b6Sdrh int oomCnt = 0; /* Counter for the OOM loop */
823048810b6Sdrh char zErrBuf[200]; /* Space for the error message */
824048810b6Sdrh const char *zFailCode; /* Value of the TEST_FAILURE environment var */
825b3df0c67Sdrh const char *zPrompt; /* Initial prompt when large-file fuzzing */
826b3df0c67Sdrh int nInFile = 0; /* Number of input files to read */
827b3df0c67Sdrh char **azInFile = 0; /* Array of input file names */
828b3df0c67Sdrh int jj; /* Loop counter for azInFile[] */
8291a57c17dSdrh sqlite3_int64 iBegin; /* Start time for the whole program */
830c843016eSdrh sqlite3_int64 iStart, iEnd; /* Start and end-times for a test case */
831f9def061Sdrh const char *zDbName = 0; /* Name of an on-disk database file to open */
8324a74d076Sdrh
8331a57c17dSdrh iBegin = timeOfDay();
834b97ad029Sdrh sqlite3_shutdown();
835048810b6Sdrh zFailCode = getenv("TEST_FAILURE");
836268e72f9Sdrh g.zArgv0 = argv[0];
837b3df0c67Sdrh zPrompt = "<stdin>";
838268e72f9Sdrh for(i=1; i<argc; i++){
839268e72f9Sdrh const char *z = argv[i];
840268e72f9Sdrh if( z[0]=='-' ){
841268e72f9Sdrh z++;
842268e72f9Sdrh if( z[0]=='-' ) z++;
8434a74d076Sdrh if( strcmp(z,"autovacuum")==0 ){
8444a74d076Sdrh doAutovac = 1;
845268e72f9Sdrh }else
846acd33745Sdrh if( strcmp(z,"database")==0 ){
847acd33745Sdrh if( i>=argc-1 ) abendError("missing argument on %s\n", argv[i]);
848acd33745Sdrh zDbName = argv[i+1];
849acd33745Sdrh i += 1;
850acd33745Sdrh }else
851b97ad029Sdrh if( strcmp(z,"disable-lookaside")==0 ){
852b97ad029Sdrh nLook = 1;
853b97ad029Sdrh szLook = 0;
854b97ad029Sdrh }else
855268e72f9Sdrh if( strcmp(z, "f")==0 && i+1<argc ){
856b3df0c67Sdrh i++;
857b3df0c67Sdrh goto addNewInFile;
858268e72f9Sdrh }else
8594a74d076Sdrh if( strcmp(z,"heap")==0 ){
8604a74d076Sdrh if( i>=argc-2 ) abendError("missing arguments on %s\n", argv[i]);
8614a74d076Sdrh nHeap = integerValue(argv[i+1]);
8624a74d076Sdrh mnHeap = integerValue(argv[i+2]);
8634a74d076Sdrh i += 2;
8644a74d076Sdrh }else
8654a74d076Sdrh if( strcmp(z,"help")==0 ){
8664a74d076Sdrh showHelp();
8674a74d076Sdrh return 0;
8684a74d076Sdrh }else
8694a74d076Sdrh if( strcmp(z,"lookaside")==0 ){
8704a74d076Sdrh if( i>=argc-2 ) abendError("missing arguments on %s", argv[i]);
8714a74d076Sdrh nLook = integerValue(argv[i+1]);
8724a74d076Sdrh szLook = integerValue(argv[i+2]);
8734a74d076Sdrh i += 2;
8744a74d076Sdrh }else
875048810b6Sdrh if( strcmp(z,"oom")==0 ){
876048810b6Sdrh oomFlag = 1;
877048810b6Sdrh }else
8784a74d076Sdrh if( strcmp(z,"pagesize")==0 ){
8794a74d076Sdrh if( i>=argc-1 ) abendError("missing argument on %s", argv[i]);
8804a74d076Sdrh pageSize = integerValue(argv[++i]);
8814a74d076Sdrh }else
8824a74d076Sdrh if( strcmp(z,"pcache")==0 ){
8834a74d076Sdrh if( i>=argc-2 ) abendError("missing arguments on %s", argv[i]);
8844a74d076Sdrh nPCache = integerValue(argv[i+1]);
8854a74d076Sdrh szPCache = integerValue(argv[i+2]);
8864a74d076Sdrh i += 2;
8874a74d076Sdrh }else
8881cbb7fa9Sdrh if( strcmp(z,"quiet")==0 || strcmp(z,"q")==0 ){
8891cbb7fa9Sdrh quietFlag = 1;
8901cbb7fa9Sdrh verboseFlag = 0;
8911cbb7fa9Sdrh }else
8924a74d076Sdrh if( strcmp(z,"scratch")==0 ){
8934a74d076Sdrh if( i>=argc-2 ) abendError("missing arguments on %s", argv[i]);
8944a74d076Sdrh nScratch = integerValue(argv[i+1]);
8954a74d076Sdrh szScratch = integerValue(argv[i+2]);
8964a74d076Sdrh i += 2;
8974a74d076Sdrh }else
898875bafa1Sdrh if( strcmp(z, "unique-cases")==0 ){
899875bafa1Sdrh if( i>=argc-1 ) abendError("missing arguments on %s", argv[i]);
900875bafa1Sdrh if( zDataOut ) abendError("only one --minimize allowed");
901875bafa1Sdrh zDataOut = argv[++i];
902875bafa1Sdrh }else
9034a74d076Sdrh if( strcmp(z,"utf16le")==0 ){
9044a74d076Sdrh zEncoding = "utf16le";
9054a74d076Sdrh }else
9064a74d076Sdrh if( strcmp(z,"utf16be")==0 ){
9074a74d076Sdrh zEncoding = "utf16be";
9084a74d076Sdrh }else
9091cbb7fa9Sdrh if( strcmp(z,"verbose")==0 || strcmp(z,"v")==0 ){
9101cbb7fa9Sdrh quietFlag = 0;
9111cbb7fa9Sdrh verboseFlag = 1;
9121cbb7fa9Sdrh }else
913268e72f9Sdrh {
914268e72f9Sdrh abendError("unknown option: %s", argv[i]);
915268e72f9Sdrh }
916268e72f9Sdrh }else{
917b3df0c67Sdrh addNewInFile:
918b3df0c67Sdrh nInFile++;
919b3df0c67Sdrh azInFile = realloc(azInFile, sizeof(azInFile[0])*nInFile);
920b3df0c67Sdrh if( azInFile==0 ) abendError("out of memory");
921b3df0c67Sdrh azInFile[nInFile-1] = argv[i];
922268e72f9Sdrh }
923268e72f9Sdrh }
924b3df0c67Sdrh
925b3df0c67Sdrh /* Do global SQLite initialization */
9260ee751fbSdrh sqlite3_config(SQLITE_CONFIG_LOG, verboseFlag ? shellLog : shellLogNoop, 0);
9274a74d076Sdrh if( nHeap>0 ){
9284a74d076Sdrh pHeap = malloc( nHeap );
9294a74d076Sdrh if( pHeap==0 ) fatalError("cannot allocate %d-byte heap\n", nHeap);
9304a74d076Sdrh rc = sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nHeap, mnHeap);
9314a74d076Sdrh if( rc ) abendError("heap configuration failed: %d\n", rc);
9324a74d076Sdrh }
933048810b6Sdrh if( oomFlag ){
934048810b6Sdrh sqlite3_config(SQLITE_CONFIG_GETMALLOC, &g.sOrigMem);
935048810b6Sdrh g.sOomMem = g.sOrigMem;
936048810b6Sdrh g.sOomMem.xMalloc = oomMalloc;
937048810b6Sdrh g.sOomMem.xRealloc = oomRealloc;
938048810b6Sdrh sqlite3_config(SQLITE_CONFIG_MALLOC, &g.sOomMem);
939048810b6Sdrh }
9404a74d076Sdrh if( nLook>0 ){
9414a74d076Sdrh sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0);
9424a74d076Sdrh if( szLook>0 ){
9434a74d076Sdrh pLook = malloc( nLook*szLook );
9444a74d076Sdrh if( pLook==0 ) fatalError("out of memory");
9454a74d076Sdrh }
9464a74d076Sdrh }
9474a74d076Sdrh if( nScratch>0 && szScratch>0 ){
9484a74d076Sdrh pScratch = malloc( nScratch*(sqlite3_int64)szScratch );
9494a74d076Sdrh if( pScratch==0 ) fatalError("cannot allocate %lld-byte scratch",
9504a74d076Sdrh nScratch*(sqlite3_int64)szScratch);
9514a74d076Sdrh rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, pScratch, szScratch, nScratch);
9524a74d076Sdrh if( rc ) abendError("scratch configuration failed: %d\n", rc);
9534a74d076Sdrh }
9544a74d076Sdrh if( nPCache>0 && szPCache>0 ){
9554a74d076Sdrh pPCache = malloc( nPCache*(sqlite3_int64)szPCache );
9564a74d076Sdrh if( pPCache==0 ) fatalError("cannot allocate %lld-byte pcache",
9574a74d076Sdrh nPCache*(sqlite3_int64)szPCache);
9584a74d076Sdrh rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, pPCache, szPCache, nPCache);
9594a74d076Sdrh if( rc ) abendError("pcache configuration failed: %d", rc);
9604a74d076Sdrh }
961b3df0c67Sdrh
962b3df0c67Sdrh /* If the --unique-cases option was supplied, open the database that will
963b3df0c67Sdrh ** be used to gather unique test cases.
964b3df0c67Sdrh */
965875bafa1Sdrh if( zDataOut ){
966875bafa1Sdrh rc = sqlite3_open(":memory:", &dataDb);
967875bafa1Sdrh if( rc ) abendError("cannot open :memory: database");
968875bafa1Sdrh rc = sqlite3_exec(dataDb,
969c843016eSdrh "CREATE TABLE testcase(sql BLOB PRIMARY KEY, tm) WITHOUT ROWID;",0,0,0);
970875bafa1Sdrh if( rc ) abendError("%s", sqlite3_errmsg(dataDb));
971b3df0c67Sdrh rc = sqlite3_prepare_v2(dataDb,
972c843016eSdrh "INSERT OR IGNORE INTO testcase(sql,tm)VALUES(?1,?2)",
973875bafa1Sdrh -1, &pStmt, 0);
974875bafa1Sdrh if( rc ) abendError("%s", sqlite3_errmsg(dataDb));
975875bafa1Sdrh }
976b3df0c67Sdrh
977b3df0c67Sdrh /* Initialize the input buffer used to hold SQL text */
978b3df0c67Sdrh if( nInFile==0 ) nInFile = 1;
979b3df0c67Sdrh nAlloc = 1000;
980b3df0c67Sdrh zIn = malloc(nAlloc);
981b3df0c67Sdrh if( zIn==0 ) fatalError("out of memory");
982b3df0c67Sdrh
983b3df0c67Sdrh /* Loop over all input files */
984b3df0c67Sdrh for(jj=0; jj<nInFile; jj++){
985b3df0c67Sdrh
986b3df0c67Sdrh /* Read the complete content of the next input file into zIn[] */
987b3df0c67Sdrh FILE *in;
988b3df0c67Sdrh if( azInFile ){
989b3df0c67Sdrh int j, k;
990b3df0c67Sdrh in = fopen(azInFile[jj],"rb");
991b3df0c67Sdrh if( in==0 ){
992b3df0c67Sdrh abendError("cannot open %s for reading", azInFile[jj]);
993f34e9aabSdrh }
994b3df0c67Sdrh zPrompt = azInFile[jj];
995b3df0c67Sdrh for(j=k=0; zPrompt[j]; j++) if( zPrompt[j]=='/' ) k = j+1;
996b3df0c67Sdrh zPrompt += k;
997b3df0c67Sdrh }else{
998b3df0c67Sdrh in = stdin;
999b3df0c67Sdrh zPrompt = "<stdin>";
1000f34e9aabSdrh }
1001b3df0c67Sdrh while( !feof(in) ){
1002b3df0c67Sdrh got = fread(zIn+nIn, 1, nAlloc-nIn-1, in);
1003b3df0c67Sdrh nIn += (int)got;
1004b3df0c67Sdrh zIn[nIn] = 0;
1005b3df0c67Sdrh if( got==0 ) break;
10061a57c17dSdrh if( nAlloc - nIn - 1 < 100 ){
1007b3df0c67Sdrh nAlloc += nAlloc+1000;
10081a57c17dSdrh zIn = realloc(zIn, nAlloc);
10091a57c17dSdrh if( zIn==0 ) fatalError("out of memory");
10101a57c17dSdrh }
1011b3df0c67Sdrh }
1012b3df0c67Sdrh if( in!=stdin ) fclose(in);
1013b3df0c67Sdrh lastPct = -1;
1014b3df0c67Sdrh
1015b3df0c67Sdrh /* Skip initial lines of the input file that begin with "#" */
1016b3df0c67Sdrh for(i=0; i<nIn; i=iNext+1){
1017e1a71a58Sdrh if( zIn[i]!='#' ) break;
1018e1a71a58Sdrh for(iNext=i+1; iNext<nIn && zIn[iNext]!='\n'; iNext++){}
1019e1a71a58Sdrh }
1020e1a71a58Sdrh nHeader = i;
1021b3df0c67Sdrh
1022b3df0c67Sdrh /* Process all test cases contained within the input file.
1023b3df0c67Sdrh */
1024b3df0c67Sdrh for(; i<nIn; i=iNext, nTest++, g.zTestName[0]=0){
1025f34e9aabSdrh char cSaved;
1026f34e9aabSdrh if( strncmp(&zIn[i], "/****<",6)==0 ){
1027f34e9aabSdrh char *z = strstr(&zIn[i], ">****/");
1028f34e9aabSdrh if( z ){
1029f34e9aabSdrh z += 6;
1030be5248f0Sdrh sqlite3_snprintf(sizeof(g.zTestName), g.zTestName, "%.*s",
1031f332071bSdrh (int)(z-&zIn[i]) - 12, &zIn[i+6]);
10329f18f743Sdrh if( verboseFlag ){
10339f18f743Sdrh printf("%.*s\n", (int)(z-&zIn[i]), &zIn[i]);
10349f18f743Sdrh fflush(stdout);
10359f18f743Sdrh }
1036f34e9aabSdrh i += (int)(z-&zIn[i]);
10371cbb7fa9Sdrh multiTest = 1;
1038f34e9aabSdrh }
1039f34e9aabSdrh }
1040f34e9aabSdrh for(iNext=i; iNext<nIn && strncmp(&zIn[iNext],"/****<",6)!=0; iNext++){}
10413fb2cc11Sdrh cSaved = zIn[iNext];
10423fb2cc11Sdrh zIn[iNext] = 0;
1043c843016eSdrh
1044b3df0c67Sdrh
1045b3df0c67Sdrh /* Print out the SQL of the next test case is --verbose is enabled
1046b3df0c67Sdrh */
1047048810b6Sdrh zSql = &zIn[i];
1048048810b6Sdrh if( verboseFlag ){
1049048810b6Sdrh printf("INPUT (offset: %d, size: %d): [%s]\n",
1050048810b6Sdrh i, (int)strlen(&zIn[i]), &zIn[i]);
1051048810b6Sdrh }else if( multiTest && !quietFlag ){
1052f332071bSdrh if( oomFlag ){
1053f332071bSdrh printf("%s\n", g.zTestName);
1054f332071bSdrh }else{
1055f332071bSdrh int pct = (10*iNext)/nIn;
1056048810b6Sdrh if( pct!=lastPct ){
1057b3df0c67Sdrh if( lastPct<0 ) printf("%s:", zPrompt);
1058f332071bSdrh printf(" %d%%", pct*10);
1059048810b6Sdrh lastPct = pct;
1060048810b6Sdrh }
1061048810b6Sdrh }
10621a57c17dSdrh }else if( nInFile>1 ){
10631a57c17dSdrh printf("%s\n", zPrompt);
1064f332071bSdrh }
1065f332071bSdrh fflush(stdout);
1066b3df0c67Sdrh
1067b3df0c67Sdrh /* Run the next test case. Run it multiple times in --oom mode
1068b3df0c67Sdrh */
1069048810b6Sdrh if( oomFlag ){
1070048810b6Sdrh oomCnt = g.iOomCntdown = 1;
1071048810b6Sdrh g.nOomFault = 0;
1072048810b6Sdrh g.bOomOnce = 1;
10739f18f743Sdrh if( verboseFlag ){
10749f18f743Sdrh printf("Once.%d\n", oomCnt);
10759f18f743Sdrh fflush(stdout);
10769f18f743Sdrh }
1077048810b6Sdrh }else{
1078048810b6Sdrh oomCnt = 0;
1079048810b6Sdrh }
1080048810b6Sdrh do{
10816918e2f9Sdrh Str sql;
10826918e2f9Sdrh StrInit(&sql);
1083acd33745Sdrh if( zDbName ){
1084acd33745Sdrh rc = sqlite3_open_v2(zDbName, &db, SQLITE_OPEN_READWRITE, 0);
1085c19bc9b6Sdrh if( rc!=SQLITE_OK ){
1086c19bc9b6Sdrh abendError("Cannot open database file %s", zDbName);
1087c19bc9b6Sdrh }
1088acd33745Sdrh }else{
1089268e72f9Sdrh rc = sqlite3_open_v2(
1090268e72f9Sdrh "main.db", &db,
1091268e72f9Sdrh SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY,
1092268e72f9Sdrh 0);
1093268e72f9Sdrh if( rc!=SQLITE_OK ){
1094268e72f9Sdrh abendError("Unable to open the in-memory database");
1095268e72f9Sdrh }
1096c19bc9b6Sdrh }
10974a74d076Sdrh if( pLook ){
10984a74d076Sdrh rc = sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE,pLook,szLook,nLook);
10994a74d076Sdrh if( rc!=SQLITE_OK ) abendError("lookaside configuration filed: %d", rc);
11004a74d076Sdrh }
110161a0d6bcSdrh #ifndef SQLITE_OMIT_TRACE
11020ee751fbSdrh sqlite3_trace(db, verboseFlag ? traceCallback : traceNoop, 0);
110361a0d6bcSdrh #endif
1104268e72f9Sdrh sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0);
1105268e72f9Sdrh sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0);
11069f6dd025Sdrh sqlite3_create_module(db, "generate_series", &seriesModule, 0);
1107f34e9aabSdrh sqlite3_limit(db, SQLITE_LIMIT_LENGTH, 1000000);
11084a74d076Sdrh if( zEncoding ) sqlexec(db, "PRAGMA encoding=%s", zEncoding);
11094a74d076Sdrh if( pageSize ) sqlexec(db, "PRAGMA pagesize=%d", pageSize);
11104a74d076Sdrh if( doAutovac ) sqlexec(db, "PRAGMA auto_vacuum=FULL");
1111c843016eSdrh iStart = timeOfDay();
11126918e2f9Sdrh
11136918e2f9Sdrh /* If using an input database file and that database contains a table
11146918e2f9Sdrh ** named "autoexec" with a column "sql", then replace the input SQL
11156918e2f9Sdrh ** with the concatenated text of the autoexec table. In this way,
11166918e2f9Sdrh ** if the database file is the input being fuzzed, the SQL text is
11176918e2f9Sdrh ** fuzzed at the same time. */
11186918e2f9Sdrh if( sqlite3_table_column_metadata(db,0,"autoexec","sql",0,0,0,0,0)==0 ){
1119*b1ed717fSmistachkin sqlite3_stmt *pStmt2;
1120*b1ed717fSmistachkin rc = sqlite3_prepare_v2(db,"SELECT sql FROM autoexec",-1,&pStmt2,0);
11216918e2f9Sdrh if( rc==SQLITE_OK ){
1122*b1ed717fSmistachkin while( sqlite3_step(pStmt2)==SQLITE_ROW ){
1123*b1ed717fSmistachkin StrAppend(&sql, (const char*)sqlite3_column_text(pStmt2, 0));
11246918e2f9Sdrh StrAppend(&sql, "\n");
11256918e2f9Sdrh }
11266918e2f9Sdrh }
1127*b1ed717fSmistachkin sqlite3_finalize(pStmt2);
11286918e2f9Sdrh zSql = StrStr(&sql);
11296918e2f9Sdrh }
11306918e2f9Sdrh
1131048810b6Sdrh g.bOomEnable = 1;
11321cbb7fa9Sdrh if( verboseFlag ){
11331cbb7fa9Sdrh zErrMsg = 0;
1134048810b6Sdrh rc = sqlite3_exec(db, zSql, execCallback, 0, &zErrMsg);
1135048810b6Sdrh if( zErrMsg ){
1136048810b6Sdrh sqlite3_snprintf(sizeof(zErrBuf),zErrBuf,"%z", zErrMsg);
1137048810b6Sdrh zErrMsg = 0;
1138048810b6Sdrh }
1139048810b6Sdrh }else {
1140048810b6Sdrh rc = sqlite3_exec(db, zSql, execNoop, 0, 0);
1141048810b6Sdrh }
1142048810b6Sdrh g.bOomEnable = 0;
1143c843016eSdrh iEnd = timeOfDay();
11446918e2f9Sdrh StrFree(&sql);
1145048810b6Sdrh rc = sqlite3_close(db);
1146048810b6Sdrh if( rc ){
1147048810b6Sdrh abendError("sqlite3_close() failed with rc=%d", rc);
1148048810b6Sdrh }
1149c843016eSdrh if( !zDataOut && sqlite3_memory_used()>0 ){
1150048810b6Sdrh abendError("memory in use after close: %lld bytes",sqlite3_memory_used());
1151048810b6Sdrh }
1152048810b6Sdrh if( oomFlag ){
11537c84c02cSdrh /* Limit the number of iterations of the OOM loop to OOM_MAX. If the
11547c84c02cSdrh ** first pass (single failure) exceeds 2/3rds of OOM_MAX this skip the
11557c84c02cSdrh ** second pass (continuous failure after first) completely. */
1156f332071bSdrh if( g.nOomFault==0 || oomCnt>OOM_MAX ){
11577c84c02cSdrh if( g.bOomOnce && oomCnt<=(OOM_MAX*2/3) ){
1158048810b6Sdrh oomCnt = g.iOomCntdown = 1;
1159048810b6Sdrh g.bOomOnce = 0;
1160048810b6Sdrh }else{
1161048810b6Sdrh oomCnt = 0;
1162048810b6Sdrh }
1163048810b6Sdrh }else{
1164048810b6Sdrh g.iOomCntdown = ++oomCnt;
1165048810b6Sdrh g.nOomFault = 0;
1166048810b6Sdrh }
1167048810b6Sdrh if( oomCnt ){
1168048810b6Sdrh if( verboseFlag ){
1169048810b6Sdrh printf("%s.%d\n", g.bOomOnce ? "Once" : "Multi", oomCnt);
11709f18f743Sdrh fflush(stdout);
1171048810b6Sdrh }
1172048810b6Sdrh nTest++;
1173048810b6Sdrh }
1174048810b6Sdrh }
1175048810b6Sdrh }while( oomCnt>0 );
1176b3df0c67Sdrh
1177c843016eSdrh /* Store unique test cases in the in the dataDb database if the
1178c843016eSdrh ** --unique-cases flag is present
1179c843016eSdrh */
1180c843016eSdrh if( zDataOut ){
1181c843016eSdrh sqlite3_bind_blob(pStmt, 1, &zIn[i], iNext-i, SQLITE_STATIC);
1182c843016eSdrh sqlite3_bind_int64(pStmt, 2, iEnd - iStart);
1183c843016eSdrh rc = sqlite3_step(pStmt);
1184c843016eSdrh if( rc!=SQLITE_DONE ) abendError("%s", sqlite3_errmsg(dataDb));
1185c843016eSdrh sqlite3_reset(pStmt);
1186c843016eSdrh }
1187c843016eSdrh
1188b3df0c67Sdrh /* Free the SQL from the current test case
1189b3df0c67Sdrh */
11909985dabbSdrh if( zToFree ){
11919985dabbSdrh sqlite3_free(zToFree);
11929985dabbSdrh zToFree = 0;
11939985dabbSdrh }
1194f34e9aabSdrh zIn[iNext] = cSaved;
1195b3df0c67Sdrh
1196b3df0c67Sdrh /* Show test-case results in --verbose mode
1197b3df0c67Sdrh */
11981cbb7fa9Sdrh if( verboseFlag ){
1199268e72f9Sdrh printf("RESULT-CODE: %d\n", rc);
1200268e72f9Sdrh if( zErrMsg ){
1201048810b6Sdrh printf("ERROR-MSG: [%s]\n", zErrBuf);
1202268e72f9Sdrh }
12039f18f743Sdrh fflush(stdout);
12041cbb7fa9Sdrh }
1205b3df0c67Sdrh
1206b3df0c67Sdrh /* Simulate an error if the TEST_FAILURE environment variable is "5".
1207b3df0c67Sdrh ** This is used to verify that automated test script really do spot
1208b3df0c67Sdrh ** errors that occur in this test program.
1209b3df0c67Sdrh */
12108ea5eca1Sdrh if( zFailCode ){
12118ea5eca1Sdrh if( zFailCode[0]=='5' && zFailCode[1]==0 ){
1212e1a71a58Sdrh abendError("simulated failure");
12138ea5eca1Sdrh }else if( zFailCode[0]!=0 ){
12148ea5eca1Sdrh /* If TEST_FAILURE is something other than 5, just exit the test
12158ea5eca1Sdrh ** early */
12168ea5eca1Sdrh printf("\nExit early due to TEST_FAILURE being set");
12178ea5eca1Sdrh break;
12188ea5eca1Sdrh }
1219f34e9aabSdrh }
1220e1a71a58Sdrh }
1221f332071bSdrh if( !verboseFlag && multiTest && !quietFlag && !oomFlag ) printf("\n");
1222b3df0c67Sdrh }
1223b3df0c67Sdrh
1224b3df0c67Sdrh /* Report total number of tests run
1225b3df0c67Sdrh */
12261cbb7fa9Sdrh if( nTest>1 && !quietFlag ){
12271a57c17dSdrh sqlite3_int64 iElapse = timeOfDay() - iBegin;
12281a57c17dSdrh printf("%s: 0 errors out of %d tests in %d.%03d seconds\nSQLite %s %s\n",
12291a57c17dSdrh g.zArgv0, nTest, (int)(iElapse/1000), (int)(iElapse%1000),
12301a57c17dSdrh sqlite3_libversion(), sqlite3_sourceid());
1231875bafa1Sdrh }
1232b3df0c67Sdrh
1233b3df0c67Sdrh /* Write the unique test cases if the --unique-cases flag was used
1234b3df0c67Sdrh */
1235875bafa1Sdrh if( zDataOut ){
1236875bafa1Sdrh int n = 0;
1237e1a71a58Sdrh FILE *out = fopen(zDataOut, "wb");
1238875bafa1Sdrh if( out==0 ) abendError("cannot open %s for writing", zDataOut);
1239e1a71a58Sdrh if( nHeader>0 ) fwrite(zIn, nHeader, 1, out);
1240875bafa1Sdrh sqlite3_finalize(pStmt);
1241c843016eSdrh rc = sqlite3_prepare_v2(dataDb, "SELECT sql, tm FROM testcase ORDER BY tm, sql",
1242c843016eSdrh -1, &pStmt, 0);
1243875bafa1Sdrh if( rc ) abendError("%s", sqlite3_errmsg(dataDb));
1244875bafa1Sdrh while( sqlite3_step(pStmt)==SQLITE_ROW ){
1245c843016eSdrh fprintf(out,"/****<%d:%dms>****/", ++n, sqlite3_column_int(pStmt,1));
1246875bafa1Sdrh fwrite(sqlite3_column_blob(pStmt,0),sqlite3_column_bytes(pStmt,0),1,out);
1247875bafa1Sdrh }
1248875bafa1Sdrh fclose(out);
1249875bafa1Sdrh sqlite3_finalize(pStmt);
1250875bafa1Sdrh sqlite3_close(dataDb);
12511cbb7fa9Sdrh }
1252b3df0c67Sdrh
1253b3df0c67Sdrh /* Clean up and exit.
1254b3df0c67Sdrh */
1255b3df0c67Sdrh free(azInFile);
1256f34e9aabSdrh free(zIn);
12574a74d076Sdrh free(pHeap);
12584a74d076Sdrh free(pLook);
12594a74d076Sdrh free(pScratch);
12604a74d076Sdrh free(pPCache);
1261f34e9aabSdrh return 0;
1262268e72f9Sdrh }
1263