xref: /sqlite-3.40.0/ext/session/changesetfuzz.c (revision 4e2d3d40)
1f095a1afSdan /*
2f095a1afSdan ** 2018-11-01
3f095a1afSdan **
4f095a1afSdan ** The author disclaims copyright to this source code.  In place of
5f095a1afSdan ** a legal notice, here is a blessing:
6f095a1afSdan **
7f095a1afSdan **    May you do good and not evil.
8f095a1afSdan **    May you find forgiveness for yourself and forgive others.
9f095a1afSdan **    May you share freely, never taking more than you give.
10f095a1afSdan **
11f095a1afSdan *************************************************************************
12f095a1afSdan ** This file contains code to implement the "changesetfuzz" command
13f095a1afSdan ** line utility for fuzzing changeset blobs without corrupting them.
14f095a1afSdan */
15f095a1afSdan 
16f095a1afSdan 
17f095a1afSdan /************************************************************************
18f095a1afSdan ** USAGE:
19f095a1afSdan **
20f095a1afSdan ** This program may be invoked in two ways:
21f095a1afSdan **
22f095a1afSdan **   changesetfuzz INPUT
23f095a1afSdan **   changesetfuzz INPUT SEED N
24f095a1afSdan **
25f095a1afSdan ** Argument INPUT must be the name of a file containing a binary changeset.
26f095a1afSdan ** In the first form above, this program outputs a human-readable version
27f095a1afSdan ** of the same changeset. This is chiefly for debugging.
28f095a1afSdan **
295704f455Sdan ** As well as changesets, this program can also dump and fuzz patchsets.
305704f455Sdan ** The term "changeset" is used for both patchsets and changesets from this
315704f455Sdan ** point on.
325704f455Sdan **
33f095a1afSdan ** In the second form, arguments SEED and N must both be integers. In this
34f095a1afSdan ** case, this program writes N binary changesets to disk. Each output
35f095a1afSdan ** changeset is a slightly modified - "fuzzed" - version of the input.
36f095a1afSdan ** The output changesets are written to files name "INPUT-$n", where $n is
37f095a1afSdan ** an integer between 0 and N-1, inclusive. Output changesets are always
38f095a1afSdan ** well-formed. Parameter SEED is used to seed the PRNG - any two
39f095a1afSdan ** invocations of this program with the same SEED and input changeset create
40f095a1afSdan ** the same N output changesets.
41f095a1afSdan **
42f095a1afSdan ** The ways in which an input changeset may be fuzzed are as follows:
43f095a1afSdan **
44f095a1afSdan **   1. Any two values within the changeset may be exchanged.
45f095a1afSdan **
46f095a1afSdan **   2. Any TEXT, BLOB, INTEGER or REAL value within the changeset
47f095a1afSdan **      may have a single bit of its content flipped.
48f095a1afSdan **
49f095a1afSdan **   3. Any value within a changeset may be replaced by a pseudo-randomly
50f095a1afSdan **      generated value.
51f095a1afSdan **
52f095a1afSdan ** The above operations never set a PRIMARY KEY column to NULL. Nor do they
53f095a1afSdan ** set any value to "undefined", or replace any "undefined" value with
54f095a1afSdan ** another. Any such operation risks producing a changeset that is not
55f095a1afSdan ** well-formed.
56f095a1afSdan **
57f095a1afSdan **   4. A single change may be duplicated.
58f095a1afSdan **
59f095a1afSdan **   5. A single change may be removed, so long as this does not mean that
60f095a1afSdan **      there are zero changes following a table-header within the changeset.
61f095a1afSdan **
62f095a1afSdan **   6. A single change may have its type (INSERT, DELETE, UPDATE) changed.
63f095a1afSdan **      If an INSERT is changed to a DELETE (or vice versa), the type is
64f095a1afSdan **      simply changed - no other modifications are required. If an INSERT
65f095a1afSdan **      or DELETE is changed to an UPDATE, then the single record is duplicated
66f095a1afSdan **      (as both the old.* and new.* records of the new UPDATE change). If an
67f095a1afSdan **      UPDATE is changed to a DELETE or INSERT, the new.* record is discarded
68f095a1afSdan **      and any "undefined" fields replaced with pseudo-randomly generated
69f095a1afSdan **      values.
70f095a1afSdan **
71f095a1afSdan **   7. An UPDATE change that modifies N table columns may be modified so
72f095a1afSdan **      that it updates N-1 columns, so long as (N>1).
73f095a1afSdan **
74005d4c61Sdan **   8. The "indirect" flag may be toggled for any change.
75005d4c61Sdan **
76005d4c61Sdan ** Entire group of changes may also be operated on:
77005d4c61Sdan **
78005d4c61Sdan **   9. Duplicate an existing group.
79005d4c61Sdan **
80005d4c61Sdan **  10. Remove an existing group.
81005d4c61Sdan **
82005d4c61Sdan **  11. The positions of two groups may be exchanged.
83005d4c61Sdan **
84005d4c61Sdan ** There are also schema changes:
85005d4c61Sdan **
86005d4c61Sdan **  12. A non-PK column may be added to a table. In this case a NULL
87005d4c61Sdan **      value is appended to all records.
88005d4c61Sdan **
89005d4c61Sdan **  13. A PK column may be added to a table. In this case a non-NULL
90005d4c61Sdan **      value is appended to all INSERT, DELETE and UPDATE old.* records.
91005d4c61Sdan **      An "undefined" is appended to new.* UPDATE records.
92005d4c61Sdan **
937844d215Sdan **  14. A column may be removed from a table, provided that it is not the
947844d215Sdan **      only PRIMARY KEY column in the table. In this case the corresponding
95005d4c61Sdan **      field is removed from all records. In cases where this leaves an UPDATE
967844d215Sdan **      with no non-PK, non-undefined fields, the entire change is removed.
97f095a1afSdan */
98f095a1afSdan 
99f095a1afSdan #include "sqlite3.h"
100f095a1afSdan #include <stdio.h>
101f095a1afSdan #include <stdlib.h>
102f095a1afSdan #include <string.h>
103f095a1afSdan #include <assert.h>
104f095a1afSdan #include <ctype.h>
105f095a1afSdan 
106f095a1afSdan #define FUZZ_VALUE_SUB       1    /* Replace one value with a copy of another */
107f095a1afSdan #define FUZZ_VALUE_MOD       2    /* Modify content by 1 bit */
108f095a1afSdan #define FUZZ_VALUE_RND       3    /* Replace with pseudo-random value */
109f095a1afSdan 
110005d4c61Sdan #define FUZZ_CHANGE_DUP      4    /* Duplicate an existing change */
111005d4c61Sdan #define FUZZ_CHANGE_DEL      5    /* Completely remove one change */
112005d4c61Sdan #define FUZZ_CHANGE_TYPE     6    /* Change the type of one change */
113005d4c61Sdan #define FUZZ_CHANGE_FIELD    7    /* Change an UPDATE to modify fewer columns */
114005d4c61Sdan #define FUZZ_CHANGE_INDIRECT 8    /* Toggle the "indirect" flag of a change */
115005d4c61Sdan 
116005d4c61Sdan #define FUZZ_GROUP_DUP       9    /* Duplicate a change group */
117005d4c61Sdan #define FUZZ_GROUP_DEL      10    /* Delete an entire change group */
118005d4c61Sdan #define FUZZ_GROUP_SWAP     11    /* Exchange the position of two groups */
119005d4c61Sdan 
120005d4c61Sdan #define FUZZ_COLUMN_ADD     12     /* Add column to table definition */
121005d4c61Sdan #define FUZZ_COLUMN_ADDPK   13     /* Add PK column to table definition */
122005d4c61Sdan #define FUZZ_COLUMN_DEL     14     /* Remove column from table definition */
123f095a1afSdan 
124f095a1afSdan 
125f095a1afSdan 
126f095a1afSdan typedef unsigned char u8;
127f095a1afSdan typedef sqlite3_uint64 u64;
128f095a1afSdan typedef sqlite3_int64 i64;
129f095a1afSdan typedef unsigned int u32;
130f095a1afSdan 
131f095a1afSdan /*
132f095a1afSdan ** Show a usage message on stderr then quit.
133f095a1afSdan */
usage(const char * argv0)134f095a1afSdan static void usage(const char *argv0){
135f095a1afSdan   fprintf(stderr, "Usage: %s FILENAME ?SEED N?\n", argv0);
136f095a1afSdan   exit(1);
137f095a1afSdan }
138f095a1afSdan 
139f095a1afSdan /*
140f095a1afSdan ** Read the content of a disk file into an in-memory buffer
141f095a1afSdan */
fuzzReadFile(const char * zFilename,int * pSz,void ** ppBuf)142f095a1afSdan static void fuzzReadFile(const char *zFilename, int *pSz, void **ppBuf){
143f095a1afSdan   FILE *f;
1442d77d80aSdrh   sqlite3_int64 sz;
145f095a1afSdan   void *pBuf;
146f095a1afSdan   f = fopen(zFilename, "rb");
147f095a1afSdan   if( f==0 ){
148f095a1afSdan     fprintf(stderr, "cannot open \"%s\" for reading\n", zFilename);
149f095a1afSdan     exit(1);
150f095a1afSdan   }
151f095a1afSdan   fseek(f, 0, SEEK_END);
1522d77d80aSdrh   sz = ftell(f);
153f095a1afSdan   rewind(f);
1542d77d80aSdrh   pBuf = sqlite3_malloc64( sz ? sz : 1 );
155f095a1afSdan   if( pBuf==0 ){
156f095a1afSdan     fprintf(stderr, "cannot allocate %d to hold content of \"%s\"\n",
157*4e2d3d40Smistachkin             (int)sz, zFilename);
158f095a1afSdan     exit(1);
159f095a1afSdan   }
160f095a1afSdan   if( sz>0 ){
161*4e2d3d40Smistachkin     if( fread(pBuf, (size_t)sz, 1, f)!=1 ){
162*4e2d3d40Smistachkin       fprintf(stderr, "cannot read all %d bytes of \"%s\"\n",
163*4e2d3d40Smistachkin               (int)sz, zFilename);
164f095a1afSdan       exit(1);
165f095a1afSdan     }
166f095a1afSdan     fclose(f);
167f095a1afSdan   }
168*4e2d3d40Smistachkin   *pSz = (int)sz;
169f095a1afSdan   *ppBuf = pBuf;
170f095a1afSdan }
171f095a1afSdan 
1727844d215Sdan /*
1737844d215Sdan ** Write the contents of buffer pBuf, size nBuf bytes, into file zFilename
1747844d215Sdan ** on disk. zFilename, if it already exists, is clobbered.
1757844d215Sdan */
fuzzWriteFile(const char * zFilename,void * pBuf,int nBuf)176f095a1afSdan static void fuzzWriteFile(const char *zFilename, void *pBuf, int nBuf){
177f095a1afSdan   FILE *f;
178f095a1afSdan   f = fopen(zFilename, "wb");
179f095a1afSdan   if( f==0 ){
180f095a1afSdan     fprintf(stderr, "cannot open \"%s\" for writing\n", zFilename);
181f095a1afSdan     exit(1);
182f095a1afSdan   }
183f095a1afSdan   if( fwrite(pBuf, nBuf, 1, f)!=1 ){
184f095a1afSdan     fprintf(stderr, "cannot write to \"%s\"\n", zFilename);
185f095a1afSdan     exit(1);
186f095a1afSdan   }
187f095a1afSdan   fclose(f);
188f095a1afSdan }
189f095a1afSdan 
fuzzCorrupt()190f095a1afSdan static int fuzzCorrupt(){
191f095a1afSdan   return SQLITE_CORRUPT;
192f095a1afSdan }
193f095a1afSdan 
194f095a1afSdan /*************************************************************************
195f095a1afSdan ** The following block is a copy of the implementation of SQLite function
196f095a1afSdan ** sqlite3_randomness. This version has two important differences:
197f095a1afSdan **
198f095a1afSdan **   1. It always uses the same seed. So the sequence of random data output
199f095a1afSdan **      is the same for every run of the program.
200f095a1afSdan **
201f095a1afSdan **   2. It is not threadsafe.
202f095a1afSdan */
203f095a1afSdan static struct sqlite3PrngType {
204f095a1afSdan   unsigned char i, j;             /* State variables */
205f095a1afSdan   unsigned char s[256];           /* State variables */
206f095a1afSdan } sqlite3Prng = {
207f095a1afSdan     0xAF, 0x28,
208f095a1afSdan   {
209f095a1afSdan     0x71, 0xF5, 0xB4, 0x6E, 0x80, 0xAB, 0x1D, 0xB8,
210f095a1afSdan     0xFB, 0xB7, 0x49, 0xBF, 0xFF, 0x72, 0x2D, 0x14,
211f095a1afSdan     0x79, 0x09, 0xE3, 0x78, 0x76, 0xB0, 0x2C, 0x0A,
212f095a1afSdan     0x8E, 0x23, 0xEE, 0xDF, 0xE0, 0x9A, 0x2F, 0x67,
213f095a1afSdan     0xE1, 0xBE, 0x0E, 0xA7, 0x08, 0x97, 0xEB, 0x77,
214f095a1afSdan     0x78, 0xBA, 0x9D, 0xCA, 0x49, 0x4C, 0x60, 0x9A,
215f095a1afSdan     0xF6, 0xBD, 0xDA, 0x7F, 0xBC, 0x48, 0x58, 0x52,
216f095a1afSdan     0xE5, 0xCD, 0x83, 0x72, 0x23, 0x52, 0xFF, 0x6D,
217f095a1afSdan     0xEF, 0x0F, 0x82, 0x29, 0xA0, 0x83, 0x3F, 0x7D,
218f095a1afSdan     0xA4, 0x88, 0x31, 0xE7, 0x88, 0x92, 0x3B, 0x9B,
219f095a1afSdan     0x3B, 0x2C, 0xC2, 0x4C, 0x71, 0xA2, 0xB0, 0xEA,
220f095a1afSdan     0x36, 0xD0, 0x00, 0xF1, 0xD3, 0x39, 0x17, 0x5D,
221f095a1afSdan     0x2A, 0x7A, 0xE4, 0xAD, 0xE1, 0x64, 0xCE, 0x0F,
222f095a1afSdan     0x9C, 0xD9, 0xF5, 0xED, 0xB0, 0x22, 0x5E, 0x62,
223f095a1afSdan     0x97, 0x02, 0xA3, 0x8C, 0x67, 0x80, 0xFC, 0x88,
224f095a1afSdan     0x14, 0x0B, 0x15, 0x10, 0x0F, 0xC7, 0x40, 0xD4,
225f095a1afSdan     0xF1, 0xF9, 0x0E, 0x1A, 0xCE, 0xB9, 0x1E, 0xA1,
226f095a1afSdan     0x72, 0x8E, 0xD7, 0x78, 0x39, 0xCD, 0xF4, 0x5D,
227f095a1afSdan     0x2A, 0x59, 0x26, 0x34, 0xF2, 0x73, 0x0B, 0xA0,
228f095a1afSdan     0x02, 0x51, 0x2C, 0x03, 0xA3, 0xA7, 0x43, 0x13,
229f095a1afSdan     0xE8, 0x98, 0x2B, 0xD2, 0x53, 0xF8, 0xEE, 0x91,
230f095a1afSdan     0x7D, 0xE7, 0xE3, 0xDA, 0xD5, 0xBB, 0xC0, 0x92,
231f095a1afSdan     0x9D, 0x98, 0x01, 0x2C, 0xF9, 0xB9, 0xA0, 0xEB,
232f095a1afSdan     0xCF, 0x32, 0xFA, 0x01, 0x49, 0xA5, 0x1D, 0x9A,
233f095a1afSdan     0x76, 0x86, 0x3F, 0x40, 0xD4, 0x89, 0x8F, 0x9C,
234f095a1afSdan     0xE2, 0xE3, 0x11, 0x31, 0x37, 0xB2, 0x49, 0x28,
235f095a1afSdan     0x35, 0xC0, 0x99, 0xB6, 0xD0, 0xBC, 0x66, 0x35,
236f095a1afSdan     0xF7, 0x83, 0x5B, 0xD7, 0x37, 0x1A, 0x2B, 0x18,
237f095a1afSdan     0xA6, 0xFF, 0x8D, 0x7C, 0x81, 0xA8, 0xFC, 0x9E,
238f095a1afSdan     0xC4, 0xEC, 0x80, 0xD0, 0x98, 0xA7, 0x76, 0xCC,
239f095a1afSdan     0x9C, 0x2F, 0x7B, 0xFF, 0x8E, 0x0E, 0xBB, 0x90,
240f095a1afSdan     0xAE, 0x13, 0x06, 0xF5, 0x1C, 0x4E, 0x52, 0xF7
241f095a1afSdan   }
242f095a1afSdan };
243f095a1afSdan 
244f095a1afSdan /*
245f095a1afSdan ** Generate and return single random byte
246f095a1afSdan */
fuzzRandomByte(void)247f095a1afSdan static unsigned char fuzzRandomByte(void){
248f095a1afSdan   unsigned char t;
249f095a1afSdan   sqlite3Prng.i++;
250f095a1afSdan   t = sqlite3Prng.s[sqlite3Prng.i];
251f095a1afSdan   sqlite3Prng.j += t;
252f095a1afSdan   sqlite3Prng.s[sqlite3Prng.i] = sqlite3Prng.s[sqlite3Prng.j];
253f095a1afSdan   sqlite3Prng.s[sqlite3Prng.j] = t;
254f095a1afSdan   t += sqlite3Prng.s[sqlite3Prng.i];
255f095a1afSdan   return sqlite3Prng.s[t];
256f095a1afSdan }
257f095a1afSdan 
258f095a1afSdan /*
259f095a1afSdan ** Return N random bytes.
260f095a1afSdan */
fuzzRandomBlob(int nBuf,unsigned char * zBuf)261f095a1afSdan static void fuzzRandomBlob(int nBuf, unsigned char *zBuf){
262f095a1afSdan   int i;
263f095a1afSdan   for(i=0; i<nBuf; i++){
264f095a1afSdan     zBuf[i] = fuzzRandomByte();
265f095a1afSdan   }
266f095a1afSdan }
267f095a1afSdan 
268f095a1afSdan /*
269f095a1afSdan ** Return a random integer between 0 and nRange (not inclusive).
270f095a1afSdan */
fuzzRandomInt(unsigned int nRange)271f095a1afSdan static unsigned int fuzzRandomInt(unsigned int nRange){
272f095a1afSdan   unsigned int ret;
273f095a1afSdan   assert( nRange>0 );
274f095a1afSdan   fuzzRandomBlob(sizeof(ret), (unsigned char*)&ret);
275f095a1afSdan   return (ret % nRange);
276f095a1afSdan }
277f095a1afSdan 
fuzzRandomU64()278f095a1afSdan static u64 fuzzRandomU64(){
279f095a1afSdan   u64 ret;
280f095a1afSdan   fuzzRandomBlob(sizeof(ret), (unsigned char*)&ret);
281f095a1afSdan   return ret;
282f095a1afSdan }
283f095a1afSdan 
fuzzRandomSeed(unsigned int iSeed)284f095a1afSdan static void fuzzRandomSeed(unsigned int iSeed){
285f095a1afSdan   int i;
286f095a1afSdan   for(i=0; i<256; i+=4){
287f095a1afSdan     sqlite3Prng.s[i] ^= ((iSeed >> 24) & 0xFF);
288f095a1afSdan     sqlite3Prng.s[i+1] ^= ((iSeed >> 16) & 0xFF);
289f095a1afSdan     sqlite3Prng.s[i+2] ^= ((iSeed >>  8) & 0xFF);
290f095a1afSdan     sqlite3Prng.s[i+3] ^= ((iSeed >>  0) & 0xFF);
291f095a1afSdan   }
292f095a1afSdan }
293f095a1afSdan /*
294f095a1afSdan ** End of code for generating pseudo-random values.
295f095a1afSdan *************************************************************************/
296f095a1afSdan 
297f095a1afSdan typedef struct FuzzChangeset FuzzChangeset;
298f095a1afSdan typedef struct FuzzChangesetGroup FuzzChangesetGroup;
299f095a1afSdan typedef struct FuzzChange FuzzChange;
300f095a1afSdan 
301f095a1afSdan /*
302f095a1afSdan ** Object containing partially parsed changeset.
303f095a1afSdan */
304f095a1afSdan struct FuzzChangeset {
3057844d215Sdan   int bPatchset;                  /* True for a patchset */
306f095a1afSdan   FuzzChangesetGroup **apGroup;   /* Array of groups in changeset */
307f095a1afSdan   int nGroup;                     /* Number of items in list pGroup */
308005d4c61Sdan   u8 **apVal;                     /* Array of all values in changeset */
309005d4c61Sdan   int nVal;                       /* Number of used slots in apVal[] */
310f095a1afSdan   int nChange;                    /* Number of changes in changeset */
311f095a1afSdan   int nUpdate;                    /* Number of UPDATE changes in changeset */
312f095a1afSdan };
313f095a1afSdan 
3147844d215Sdan /*
3157844d215Sdan ** There is one object of this type for each change-group (table header)
3167844d215Sdan ** in the input changeset.
3177844d215Sdan */
318f095a1afSdan struct FuzzChangesetGroup {
319f095a1afSdan   const char *zTab;               /* Name of table */
320f095a1afSdan   int nCol;                       /* Number of columns in table */
321f095a1afSdan   u8 *aPK;                        /* PK array for this table */
322f095a1afSdan   u8 *aChange;                    /* Buffer containing array of changes */
323f095a1afSdan   int szChange;                   /* Size of buffer aChange[] in bytes */
324f095a1afSdan   int nChange;                    /* Number of changes in buffer aChange[] */
325f095a1afSdan };
326f095a1afSdan 
327f095a1afSdan /*
328f095a1afSdan ** Description of a fuzz change to be applied to a changeset.
329f095a1afSdan */
330f095a1afSdan struct FuzzChange {
331f095a1afSdan   int eType;                      /* One of the FUZZ_* constants above */
332005d4c61Sdan   int iChange;                    /* Change or UPDATE to modify */
333005d4c61Sdan   int iGroup;                     /* Group to modify */
334005d4c61Sdan   int iDelete;                    /* Field to remove (FUZZ_COLUMN_DEL) */
3357844d215Sdan   u8 *pSub1;                      /* Replace this value with pSub2 */
3367844d215Sdan   u8 *pSub2;                      /* And this one with pSub1 */
3377844d215Sdan   u8 aSub[128];                   /* Buffer for substitute value */
338f095a1afSdan   int iCurrent;                   /* Current change number */
339f095a1afSdan };
340f095a1afSdan 
3417844d215Sdan /*
3427844d215Sdan ** Allocate and return nByte bytes of zeroed memory.
3437844d215Sdan */
fuzzMalloc(sqlite3_int64 nByte)3442d77d80aSdrh static void *fuzzMalloc(sqlite3_int64 nByte){
3452d77d80aSdrh   void *pRet = sqlite3_malloc64(nByte);
346f095a1afSdan   if( pRet ){
347*4e2d3d40Smistachkin     memset(pRet, 0, (size_t)nByte);
348f095a1afSdan   }
349f095a1afSdan   return pRet;
350f095a1afSdan }
351f095a1afSdan 
3527844d215Sdan /*
3537844d215Sdan ** Free the buffer indicated by the first argument. This function is used
3547844d215Sdan ** to free buffers allocated by fuzzMalloc().
3557844d215Sdan */
fuzzFree(void * p)356f095a1afSdan static void fuzzFree(void *p){
357f095a1afSdan   sqlite3_free(p);
358f095a1afSdan }
359f095a1afSdan 
3607844d215Sdan /*
3617844d215Sdan ** Argument p points to a buffer containing an SQLite varint that, assuming the
3627844d215Sdan ** input is not corrupt, may be between 0 and 0x7FFFFFFF, inclusive. Before
3637844d215Sdan ** returning, this function sets (*pnVal) to the value of that varint, and
3647844d215Sdan ** returns the number of bytes of space that it takes up.
3657844d215Sdan */
fuzzGetVarint(u8 * p,int * pnVal)366f095a1afSdan static int fuzzGetVarint(u8 *p, int *pnVal){
367f095a1afSdan   int i;
368f095a1afSdan   sqlite3_uint64 nVal = 0;
369f095a1afSdan   for(i=0; i<9; i++){
370f095a1afSdan     nVal = (nVal<<7) + (p[i] & 0x7F);
371f095a1afSdan     if( (p[i] & 0x80)==0 ){
372f095a1afSdan       i++;
373f095a1afSdan       break;
374f095a1afSdan     }
375f095a1afSdan   }
376f095a1afSdan   *pnVal = (int)nVal;
377f095a1afSdan   return i;
378f095a1afSdan }
379f095a1afSdan 
3807844d215Sdan /*
3817844d215Sdan ** Write value nVal into the buffer indicated by argument p as an SQLite
3827844d215Sdan ** varint. nVal is guaranteed to be between 0 and (2^21-1), inclusive.
3837844d215Sdan ** Return the number of bytes written to buffer p.
3847844d215Sdan */
fuzzPutVarint(u8 * p,int nVal)385f095a1afSdan static int fuzzPutVarint(u8 *p, int nVal){
386f095a1afSdan   assert( nVal>0 && nVal<2097152 );
387f095a1afSdan   if( nVal<128 ){
388*4e2d3d40Smistachkin     p[0] = (u8)nVal;
389f095a1afSdan     return 1;
390f095a1afSdan   }
391f095a1afSdan   if( nVal<16384 ){
392f095a1afSdan     p[0] = ((nVal >> 7) & 0x7F) | 0x80;
393f095a1afSdan     p[1] = (nVal & 0x7F);
394f095a1afSdan     return 2;
395f095a1afSdan   }
396f095a1afSdan 
397f095a1afSdan   p[0] = ((nVal >> 14) & 0x7F) | 0x80;
398f095a1afSdan   p[1] = ((nVal >> 7) & 0x7F) | 0x80;
399f095a1afSdan   p[2] = (nVal & 0x7F);
400f095a1afSdan   return 3;
401f095a1afSdan }
402f095a1afSdan 
403f095a1afSdan /*
404f095a1afSdan ** Read a 64-bit big-endian integer value from buffer aRec[]. Return
405f095a1afSdan ** the value read.
406f095a1afSdan */
fuzzGetI64(u8 * aRec)4077844d215Sdan static i64 fuzzGetI64(u8 *aRec){
4087844d215Sdan   return (i64)(
4097844d215Sdan       (((u64)aRec[0]) << 56)
4107844d215Sdan     + (((u64)aRec[1]) << 48)
4117844d215Sdan     + (((u64)aRec[2]) << 40)
4127844d215Sdan     + (((u64)aRec[3]) << 32)
4137844d215Sdan     + (((u64)aRec[4]) << 24)
4147844d215Sdan     + (((u64)aRec[5]) << 16)
4157844d215Sdan     + (((u64)aRec[6]) <<  8)
4167844d215Sdan     + (((u64)aRec[7]) <<  0)
4177844d215Sdan   );
418f095a1afSdan }
419f095a1afSdan 
4207844d215Sdan /*
4217844d215Sdan ** Write value iVal to buffer aRec[] as an unsigned 64-bit big-endian integer.
4227844d215Sdan */
fuzzPutU64(u8 * aRec,u64 iVal)423f095a1afSdan static void fuzzPutU64(u8 *aRec, u64 iVal){
424f095a1afSdan   aRec[0] = (iVal>>56) & 0xFF;
425f095a1afSdan   aRec[1] = (iVal>>48) & 0xFF;
426f095a1afSdan   aRec[2] = (iVal>>40) & 0xFF;
427f095a1afSdan   aRec[3] = (iVal>>32) & 0xFF;
428f095a1afSdan   aRec[4] = (iVal>>24) & 0xFF;
429f095a1afSdan   aRec[5] = (iVal>>16) & 0xFF;
430f095a1afSdan   aRec[6] = (iVal>> 8) & 0xFF;
431f095a1afSdan   aRec[7] = (iVal)     & 0xFF;
432f095a1afSdan }
433f095a1afSdan 
4345704f455Sdan /*
4355704f455Sdan ** Parse a single table-header from the input. Allocate a new change-group
4365704f455Sdan ** object with the results. Return SQLITE_OK if successful, or an error code
4375704f455Sdan ** otherwise.
4385704f455Sdan */
fuzzParseHeader(FuzzChangeset * pParse,u8 ** ppHdr,u8 * pEnd,FuzzChangesetGroup ** ppGrp)4397844d215Sdan static int fuzzParseHeader(
4405704f455Sdan   FuzzChangeset *pParse,          /* Changeset parse object */
4415704f455Sdan   u8 **ppHdr,                     /* IN/OUT: Iterator */
4425704f455Sdan   u8 *pEnd,                       /* 1 byte past EOF */
4435704f455Sdan   FuzzChangesetGroup **ppGrp      /* OUT: New change-group object */
4447844d215Sdan ){
445f095a1afSdan   int rc = SQLITE_OK;
446f095a1afSdan   FuzzChangesetGroup *pGrp;
4477844d215Sdan   u8 cHdr = (pParse->bPatchset ? 'P' : 'T');
448f095a1afSdan 
449f095a1afSdan   assert( pEnd>(*ppHdr) );
450f095a1afSdan   pGrp = (FuzzChangesetGroup*)fuzzMalloc(sizeof(FuzzChangesetGroup));
451f095a1afSdan   if( !pGrp ){
452f095a1afSdan     rc = SQLITE_NOMEM;
453f095a1afSdan   }else{
454f095a1afSdan     u8 *p = *ppHdr;
4557844d215Sdan     if( p[0]!=cHdr ){
456f095a1afSdan       rc = fuzzCorrupt();
457f095a1afSdan     }else{
458f095a1afSdan       p++;
459f095a1afSdan       p += fuzzGetVarint(p, &pGrp->nCol);
460f095a1afSdan       pGrp->aPK = p;
461f095a1afSdan       p += pGrp->nCol;
462f095a1afSdan       pGrp->zTab = (const char*)p;
463*4e2d3d40Smistachkin       p = &p[strlen((const char*)p)+1];
464f095a1afSdan 
465f095a1afSdan       if( p>=pEnd ){
466f095a1afSdan         rc = fuzzCorrupt();
467f095a1afSdan       }
468f095a1afSdan     }
469f095a1afSdan     *ppHdr = p;
470f095a1afSdan   }
471f095a1afSdan 
472f095a1afSdan   if( rc!=SQLITE_OK ){
473f095a1afSdan     fuzzFree(pGrp);
474f095a1afSdan     pGrp = 0;
475f095a1afSdan   }
476f095a1afSdan 
477f095a1afSdan   *ppGrp = pGrp;
478f095a1afSdan   return rc;
479f095a1afSdan }
480f095a1afSdan 
4815704f455Sdan /*
4825704f455Sdan ** Argument p points to a buffer containing a single changeset-record value.
4835704f455Sdan ** This function attempts to determine the size of the value in bytes. If
4845704f455Sdan ** successful, it sets (*pSz) to the size and returns SQLITE_OK. Or, if the
4855704f455Sdan ** buffer does not contain a valid value, SQLITE_CORRUPT is returned and
4865704f455Sdan ** the final value of (*pSz) is undefined.
4875704f455Sdan */
fuzzChangeSize(u8 * p,int * pSz)488f095a1afSdan static int fuzzChangeSize(u8 *p, int *pSz){
489f095a1afSdan   u8 eType = p[0];
490f095a1afSdan   switch( eType ){
491f095a1afSdan     case 0x00:                    /* undefined */
492f095a1afSdan     case 0x05:                    /* null */
493f095a1afSdan       *pSz = 1;
494f095a1afSdan       break;
495f095a1afSdan 
496f095a1afSdan     case 0x01:                    /* integer */
497f095a1afSdan     case 0x02:                    /* real */
498f095a1afSdan       *pSz = 9;
499f095a1afSdan       break;
500f095a1afSdan 
501f095a1afSdan     case 0x03:                    /* text */
502f095a1afSdan     case 0x04: {                  /* blob */
503f095a1afSdan       int nTxt;
504f095a1afSdan       int sz;
505f095a1afSdan       sz = fuzzGetVarint(&p[1], &nTxt);
506f095a1afSdan       *pSz = 1 + sz + nTxt;
507f095a1afSdan       break;
508f095a1afSdan     }
509f095a1afSdan 
510f095a1afSdan     default:
511f095a1afSdan       return fuzzCorrupt();
512f095a1afSdan   }
513f095a1afSdan   return SQLITE_OK;
514f095a1afSdan }
515f095a1afSdan 
5165704f455Sdan /*
5175704f455Sdan ** When this function is called, (*ppRec) points to the start of a
5185704f455Sdan ** record in a changeset being parsed. This function adds entries
5195704f455Sdan ** to the pParse->apVal[] array for all values and advances (*ppRec)
5205704f455Sdan ** to one byte past the end of the record. Argument pEnd points to
5215704f455Sdan ** one byte past the end of the input changeset.
5225704f455Sdan **
5235704f455Sdan ** Argument bPkOnly is true if the record being parsed is part of
5245704f455Sdan ** a DELETE record in a patchset. In this case, all non-primary-key
5255704f455Sdan ** fields have been omitted from the record.
5265704f455Sdan **
5275704f455Sdan ** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
5285704f455Sdan */
fuzzParseRecord(u8 ** ppRec,u8 * pEnd,FuzzChangeset * pParse,int bPkOnly)5297844d215Sdan static int fuzzParseRecord(
5307844d215Sdan   u8 **ppRec,                     /* IN/OUT: Iterator */
5317844d215Sdan   u8 *pEnd,                       /* One byte after end of input data */
5325704f455Sdan   FuzzChangeset *pParse,          /* Changeset parse context */
5335704f455Sdan   int bPkOnly                     /* True if non-PK fields omitted */
5347844d215Sdan ){
535f095a1afSdan   int rc = SQLITE_OK;
5367844d215Sdan   FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1];
537f095a1afSdan   int i;
538f095a1afSdan   u8 *p = *ppRec;
539f095a1afSdan 
540dbc1e9e6Sdan   for(i=0; rc==SQLITE_OK && i<pGrp->nCol; i++){
5417844d215Sdan     if( bPkOnly==0 || pGrp->aPK[i] ){
542f095a1afSdan       int sz;
543dbc1e9e6Sdan       if( p>=pEnd ) break;
544005d4c61Sdan       if( (pParse->nVal & (pParse->nVal-1))==0 ){
545005d4c61Sdan         int nNew = pParse->nVal ? pParse->nVal*2 : 4;
546005d4c61Sdan         u8 **apNew = (u8**)sqlite3_realloc(pParse->apVal, nNew*sizeof(u8*));
547005d4c61Sdan         if( apNew==0 ) return SQLITE_NOMEM;
548005d4c61Sdan         pParse->apVal = apNew;
549f095a1afSdan       }
550005d4c61Sdan       pParse->apVal[pParse->nVal++] = p;
551f095a1afSdan       rc = fuzzChangeSize(p, &sz);
552f095a1afSdan       p += sz;
553f095a1afSdan     }
5547844d215Sdan   }
555f095a1afSdan 
5567844d215Sdan   if( rc==SQLITE_OK && i<pGrp->nCol ){
557f095a1afSdan     rc = fuzzCorrupt();
558f095a1afSdan   }
559f095a1afSdan 
560f095a1afSdan   *ppRec = p;
561f095a1afSdan   return rc;
562f095a1afSdan }
563f095a1afSdan 
5645704f455Sdan /*
5655704f455Sdan ** Parse the array of changes starting at (*ppData) and add entries for
5665704f455Sdan ** all values to the pParse->apVal[] array. Argument pEnd points to one byte
5675704f455Sdan ** past the end of the input changeset. If successful, set (*ppData) to point
5685704f455Sdan ** to one byte past the end of the change array and return SQLITE_OK.
5695704f455Sdan ** Otherwise, return an SQLite error code. The final value of (*ppData) is
5705704f455Sdan ** undefined in this case.
5715704f455Sdan */
fuzzParseChanges(u8 ** ppData,u8 * pEnd,FuzzChangeset * pParse)572f095a1afSdan static int fuzzParseChanges(u8 **ppData, u8 *pEnd, FuzzChangeset *pParse){
5737844d215Sdan   u8 cHdr = (pParse->bPatchset ? 'P' : 'T');
574f095a1afSdan   FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1];
575f095a1afSdan   int rc = SQLITE_OK;
576f095a1afSdan   u8 *p = *ppData;
577f095a1afSdan 
578f095a1afSdan   pGrp->aChange = p;
5797844d215Sdan   while( rc==SQLITE_OK && p<pEnd && p[0]!=cHdr ){
580f095a1afSdan     u8 eOp = p[0];
581f095a1afSdan     u8 bIndirect = p[1];
582f095a1afSdan 
583f095a1afSdan     p += 2;
584f095a1afSdan     if( eOp==SQLITE_UPDATE ){
585f095a1afSdan       pParse->nUpdate++;
5867844d215Sdan       if( pParse->bPatchset==0 ){
5877844d215Sdan         rc = fuzzParseRecord(&p, pEnd, pParse, 0);
5887844d215Sdan       }
589f095a1afSdan     }else if( eOp!=SQLITE_INSERT && eOp!=SQLITE_DELETE ){
590f095a1afSdan       rc = fuzzCorrupt();
591f095a1afSdan     }
592f095a1afSdan     if( rc==SQLITE_OK ){
5937844d215Sdan       int bPkOnly = (eOp==SQLITE_DELETE && pParse->bPatchset);
5947844d215Sdan       rc = fuzzParseRecord(&p, pEnd, pParse, bPkOnly);
595f095a1afSdan     }
596f095a1afSdan     pGrp->nChange++;
597f095a1afSdan     pParse->nChange++;
598f095a1afSdan   }
599f095a1afSdan   pGrp->szChange = p - pGrp->aChange;
600f095a1afSdan 
601f095a1afSdan   *ppData = p;
602f095a1afSdan   return rc;
603f095a1afSdan }
604f095a1afSdan 
6055704f455Sdan /*
6065704f455Sdan ** Parse the changeset stored in buffer pChangeset (nChangeset bytes in
6075704f455Sdan ** size). If successful, write the results into (*pParse) and return
6085704f455Sdan ** SQLITE_OK. Or, if an error occurs, return an SQLite error code. The
6095704f455Sdan ** final state of (*pParse) is undefined in this case.
6105704f455Sdan */
fuzzParseChangeset(u8 * pChangeset,int nChangeset,FuzzChangeset * pParse)611f095a1afSdan static int fuzzParseChangeset(
612f095a1afSdan   u8 *pChangeset,                 /* Buffer containing changeset */
613f095a1afSdan   int nChangeset,                 /* Size of buffer in bytes */
614f095a1afSdan   FuzzChangeset *pParse           /* OUT: Results of parse */
615f095a1afSdan ){
616f095a1afSdan   u8 *pEnd = &pChangeset[nChangeset];
617f095a1afSdan   u8 *p = pChangeset;
618f095a1afSdan   int rc = SQLITE_OK;
619f095a1afSdan 
620f095a1afSdan   memset(pParse, 0, sizeof(FuzzChangeset));
6217844d215Sdan   if( nChangeset>0 ){
6227844d215Sdan     pParse->bPatchset = (pChangeset[0]=='P');
6237844d215Sdan   }
624f095a1afSdan 
625f095a1afSdan   while( rc==SQLITE_OK && p<pEnd ){
626f095a1afSdan     FuzzChangesetGroup *pGrp = 0;
627f095a1afSdan 
628f095a1afSdan     /* Read a table-header from the changeset */
6297844d215Sdan     rc = fuzzParseHeader(pParse, &p, pEnd, &pGrp);
630f095a1afSdan     assert( (rc==SQLITE_OK)==(pGrp!=0) );
631f095a1afSdan 
6327844d215Sdan     /* If the table-header was successfully parsed, add the new change-group
6337844d215Sdan     ** to the array and parse the associated changes. */
634f095a1afSdan     if( rc==SQLITE_OK ){
6352d77d80aSdrh       FuzzChangesetGroup **apNew = (FuzzChangesetGroup**)sqlite3_realloc64(
636f095a1afSdan           pParse->apGroup, sizeof(FuzzChangesetGroup*)*(pParse->nGroup+1)
637f095a1afSdan       );
638f095a1afSdan       if( apNew==0 ){
639f095a1afSdan         rc = SQLITE_NOMEM;
640f095a1afSdan       }else{
641f095a1afSdan         apNew[pParse->nGroup] = pGrp;
642f095a1afSdan         pParse->apGroup = apNew;
643f095a1afSdan         pParse->nGroup++;
644f095a1afSdan       }
645f095a1afSdan       rc = fuzzParseChanges(&p, pEnd, pParse);
646f095a1afSdan     }
647f095a1afSdan   }
648f095a1afSdan 
649f095a1afSdan   return rc;
650f095a1afSdan }
651f095a1afSdan 
6525704f455Sdan /*
6535704f455Sdan ** When this function is called, (*ppRec) points to the first byte of
6545704f455Sdan ** a record that is part of change-group pGrp. This function attempts
6555704f455Sdan ** to output a human-readable version of the record to stdout and advance
6565704f455Sdan ** (*ppRec) to point to the first byte past the end of the record before
6575704f455Sdan ** returning. If successful, SQLITE_OK is returned. Otherwise, an SQLite
6585704f455Sdan ** error code.
6595704f455Sdan **
6605704f455Sdan ** If parameter bPkOnly is non-zero, then all non-primary-key fields have
6615704f455Sdan ** been omitted from the record. This occurs for records that are part
6625704f455Sdan ** of DELETE changes in patchsets.
6635704f455Sdan */
fuzzPrintRecord(FuzzChangesetGroup * pGrp,u8 ** ppRec,int bPKOnly)6647844d215Sdan static int fuzzPrintRecord(FuzzChangesetGroup *pGrp, u8 **ppRec, int bPKOnly){
665f095a1afSdan   int rc = SQLITE_OK;
666f095a1afSdan   u8 *p = *ppRec;
667f095a1afSdan   int i;
668f095a1afSdan   const char *zPre = " (";
669f095a1afSdan 
670f095a1afSdan   for(i=0; i<pGrp->nCol; i++){
6717844d215Sdan     if( bPKOnly==0 || pGrp->aPK[i] ){
672f095a1afSdan       u8 eType = p++[0];
673f095a1afSdan       switch( eType ){
674f095a1afSdan         case 0x00:                    /* undefined */
675f095a1afSdan           printf("%sn/a", zPre);
676f095a1afSdan           break;
677f095a1afSdan 
678f095a1afSdan         case 0x01: {                  /* integer */
679f095a1afSdan           sqlite3_int64 iVal = 0;
680f095a1afSdan           iVal = fuzzGetI64(p);
681f095a1afSdan           printf("%s%lld", zPre, iVal);
682f095a1afSdan           p += 8;
683f095a1afSdan           break;
684f095a1afSdan         }
685f095a1afSdan 
686f095a1afSdan         case 0x02: {                  /* real */
687f095a1afSdan           sqlite3_int64 iVal = 0;
688f095a1afSdan           double fVal = 0.0;
689f095a1afSdan           iVal = fuzzGetI64(p);
690f095a1afSdan           memcpy(&fVal, &iVal, 8);
691f095a1afSdan           printf("%s%f", zPre, fVal);
692f095a1afSdan           p += 8;
693f095a1afSdan           break;
694f095a1afSdan         }
695f095a1afSdan 
696f095a1afSdan         case 0x03:                    /* text */
697f095a1afSdan         case 0x04: {                  /* blob */
698f095a1afSdan           int nTxt;
699f095a1afSdan           p += fuzzGetVarint(p, &nTxt);
700f095a1afSdan           printf("%s%s", zPre, eType==0x03 ? "'" : "X'");
701f095a1afSdan           for(i=0; i<nTxt; i++){
702f095a1afSdan             if( eType==0x03 ){
703f095a1afSdan               printf("%c", p[i]);
704f095a1afSdan             }else{
705f095a1afSdan               char aHex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
706f095a1afSdan                                '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
707f095a1afSdan               };
708f095a1afSdan               printf("%c", aHex[ p[i]>>4 ]);
709f095a1afSdan               printf("%c", aHex[ p[i] & 0x0F ]);
710f095a1afSdan             }
711f095a1afSdan           }
712f095a1afSdan           printf("'");
713f095a1afSdan           p += nTxt;
714f095a1afSdan           break;
715f095a1afSdan         }
716f095a1afSdan 
717f095a1afSdan         case 0x05:                    /* null */
718f095a1afSdan           printf("%sNULL", zPre);
719f095a1afSdan           break;
720f095a1afSdan       }
721f095a1afSdan       zPre = ", ";
722f095a1afSdan     }
7237844d215Sdan   }
724f095a1afSdan   printf(")");
725f095a1afSdan 
726f095a1afSdan   *ppRec = p;
727f095a1afSdan   return rc;
728f095a1afSdan }
729f095a1afSdan 
7305704f455Sdan /*
7315704f455Sdan ** Print a human-readable version of the table-header and all changes in the
7325704f455Sdan ** change-group passed as the second argument.
7335704f455Sdan */
fuzzPrintGroup(FuzzChangeset * pParse,FuzzChangesetGroup * pGrp)7345704f455Sdan static void fuzzPrintGroup(FuzzChangeset *pParse, FuzzChangesetGroup *pGrp){
735f095a1afSdan   int i;
736f095a1afSdan   u8 *p;
737f095a1afSdan 
738f095a1afSdan   /* The table header */
739f095a1afSdan   printf("TABLE:  %s nCol=%d aPK=", pGrp->zTab, pGrp->nCol);
740f095a1afSdan   for(i=0; i<pGrp->nCol; i++){
741f095a1afSdan     printf("%d", (int)pGrp->aPK[i]);
742f095a1afSdan   }
743f095a1afSdan   printf("\n");
744f095a1afSdan 
745f095a1afSdan   /* The array of changes */
746f095a1afSdan   p = pGrp->aChange;
747f095a1afSdan   for(i=0; i<pGrp->nChange; i++){
748f095a1afSdan     u8 eType = p[0];
749f095a1afSdan     u8 bIndirect = p[1];
750f095a1afSdan     printf("%s (ind=%d):",
751f095a1afSdan         (eType==SQLITE_INSERT) ? "INSERT" :
752f095a1afSdan         (eType==SQLITE_DELETE ? "DELETE" : "UPDATE"),
753f095a1afSdan         bIndirect
754f095a1afSdan     );
755f095a1afSdan     p += 2;
756f095a1afSdan 
7577844d215Sdan     if( pParse->bPatchset==0 && eType==SQLITE_UPDATE ){
7587844d215Sdan       fuzzPrintRecord(pGrp, &p, 0);
759f095a1afSdan     }
7607844d215Sdan     fuzzPrintRecord(pGrp, &p, eType==SQLITE_DELETE && pParse->bPatchset);
761f095a1afSdan     printf("\n");
762f095a1afSdan   }
763f095a1afSdan }
764f095a1afSdan 
7655704f455Sdan /*
7665704f455Sdan ** Initialize the object passed as the second parameter with details
7675704f455Sdan ** of the change that will be attempted (type of change, to which part of the
7685704f455Sdan ** changeset it applies etc.). If successful, return SQLITE_OK. Or, if an
7695704f455Sdan ** error occurs, return an SQLite error code.
7705704f455Sdan **
7715704f455Sdan ** If a negative value is returned, then the selected change would have
7725704f455Sdan ** produced a non-well-formed changeset. In this case the caller should
7735704f455Sdan ** call this function again.
7745704f455Sdan */
fuzzSelectChange(FuzzChangeset * pParse,FuzzChange * pChange)775f095a1afSdan static int fuzzSelectChange(FuzzChangeset *pParse, FuzzChange *pChange){
776f095a1afSdan   int iSub;
777f095a1afSdan 
778f095a1afSdan   memset(pChange, 0, sizeof(FuzzChange));
7797844d215Sdan   pChange->eType = fuzzRandomInt(FUZZ_COLUMN_DEL) + 1;
780f095a1afSdan 
781f095a1afSdan   assert( pChange->eType==FUZZ_VALUE_SUB
782f095a1afSdan        || pChange->eType==FUZZ_VALUE_MOD
783f095a1afSdan        || pChange->eType==FUZZ_VALUE_RND
784f095a1afSdan        || pChange->eType==FUZZ_CHANGE_DUP
785f095a1afSdan        || pChange->eType==FUZZ_CHANGE_DEL
786f095a1afSdan        || pChange->eType==FUZZ_CHANGE_TYPE
787f095a1afSdan        || pChange->eType==FUZZ_CHANGE_FIELD
788005d4c61Sdan        || pChange->eType==FUZZ_CHANGE_INDIRECT
789005d4c61Sdan        || pChange->eType==FUZZ_GROUP_DUP
790005d4c61Sdan        || pChange->eType==FUZZ_GROUP_DEL
791005d4c61Sdan        || pChange->eType==FUZZ_GROUP_SWAP
792005d4c61Sdan        || pChange->eType==FUZZ_COLUMN_ADD
793005d4c61Sdan        || pChange->eType==FUZZ_COLUMN_ADDPK
794005d4c61Sdan        || pChange->eType==FUZZ_COLUMN_DEL
795f095a1afSdan   );
796f095a1afSdan 
797005d4c61Sdan   pChange->iGroup = fuzzRandomInt(pParse->nGroup);
798f095a1afSdan   pChange->iChange = fuzzRandomInt(pParse->nChange);
799f095a1afSdan   if( pChange->eType==FUZZ_CHANGE_FIELD ){
800f095a1afSdan     if( pParse->nUpdate==0 ) return -1;
801f095a1afSdan     pChange->iChange = fuzzRandomInt(pParse->nUpdate);
802f095a1afSdan   }
803f095a1afSdan 
804005d4c61Sdan   pChange->iDelete = -1;
805005d4c61Sdan   if( pChange->eType==FUZZ_COLUMN_DEL ){
806005d4c61Sdan     FuzzChangesetGroup *pGrp = pParse->apGroup[pChange->iGroup];
807005d4c61Sdan     int i;
808005d4c61Sdan     pChange->iDelete = fuzzRandomInt(pGrp->nCol);
809005d4c61Sdan     for(i=pGrp->nCol-1; i>=0; i--){
810005d4c61Sdan       if( pGrp->aPK[i] && pChange->iDelete!=i ) break;
811005d4c61Sdan     }
812005d4c61Sdan     if( i<0 ) return -1;
813005d4c61Sdan   }
814005d4c61Sdan 
815005d4c61Sdan   if( pChange->eType==FUZZ_GROUP_SWAP ){
816005d4c61Sdan     FuzzChangesetGroup *pGrp;
817005d4c61Sdan     int iGrp = pChange->iGroup;
818005d4c61Sdan     if( pParse->nGroup==1 ) return -1;
819005d4c61Sdan     while( iGrp==pChange->iGroup ){
820005d4c61Sdan       iGrp = fuzzRandomInt(pParse->nGroup);
821005d4c61Sdan     }
822005d4c61Sdan     pGrp = pParse->apGroup[pChange->iGroup];
823005d4c61Sdan     pParse->apGroup[pChange->iGroup] = pParse->apGroup[iGrp];
824005d4c61Sdan     pParse->apGroup[iGrp] = pGrp;
825005d4c61Sdan   }
826005d4c61Sdan 
827f095a1afSdan   if( pChange->eType==FUZZ_VALUE_SUB
828f095a1afSdan    || pChange->eType==FUZZ_VALUE_MOD
829f095a1afSdan    || pChange->eType==FUZZ_VALUE_RND
830f095a1afSdan   ){
831f095a1afSdan     iSub = fuzzRandomInt(pParse->nVal);
832005d4c61Sdan     pChange->pSub1 = pParse->apVal[iSub];
833f095a1afSdan     if( pChange->eType==FUZZ_VALUE_SUB ){
834f095a1afSdan       iSub = fuzzRandomInt(pParse->nVal);
835005d4c61Sdan       pChange->pSub2 = pParse->apVal[iSub];
836f095a1afSdan     }else{
837f095a1afSdan       pChange->pSub2 = pChange->aSub;
838f095a1afSdan     }
839f095a1afSdan 
840f095a1afSdan     if( pChange->eType==FUZZ_VALUE_RND ){
841f095a1afSdan       pChange->aSub[0] = (u8)(fuzzRandomInt(5) + 1);
842f095a1afSdan       switch( pChange->aSub[0] ){
843f095a1afSdan         case 0x01: {                  /* integer */
844f095a1afSdan           u64 iVal = fuzzRandomU64();
845f095a1afSdan           fuzzPutU64(&pChange->aSub[1], iVal);
846f095a1afSdan           break;
847f095a1afSdan         }
848f095a1afSdan 
849f095a1afSdan         case 0x02: {                  /* real */
850f095a1afSdan           u64 iVal1 = fuzzRandomU64();
851f095a1afSdan           u64 iVal2 = fuzzRandomU64();
852f095a1afSdan           double d = (double)iVal1 / (double)iVal2;
853f095a1afSdan           memcpy(&iVal1, &d, sizeof(iVal1));
854f095a1afSdan           fuzzPutU64(&pChange->aSub[1], iVal1);
855f095a1afSdan           break;
856f095a1afSdan         }
857f095a1afSdan 
858f095a1afSdan         case 0x03:                    /* text */
859f095a1afSdan         case 0x04: {                  /* blob */
860f095a1afSdan           int nByte = fuzzRandomInt(48);
861*4e2d3d40Smistachkin           pChange->aSub[1] = (u8)nByte;
862f095a1afSdan           fuzzRandomBlob(nByte, &pChange->aSub[2]);
863f095a1afSdan           if( pChange->aSub[0]==0x03 ){
864f095a1afSdan             int i;
865f095a1afSdan             for(i=0; i<nByte; i++){
866f095a1afSdan               pChange->aSub[2+i] &= 0x7F;
867f095a1afSdan             }
868f095a1afSdan           }
869f095a1afSdan           break;
870f095a1afSdan         }
871f095a1afSdan       }
872f095a1afSdan     }
873f095a1afSdan     if( pChange->eType==FUZZ_VALUE_MOD ){
874f095a1afSdan       int sz;
875f095a1afSdan       int iMod = -1;
876f095a1afSdan       fuzzChangeSize(pChange->pSub1, &sz);
877f095a1afSdan       memcpy(pChange->aSub, pChange->pSub1, sz);
878f095a1afSdan       switch( pChange->aSub[0] ){
879f095a1afSdan         case 0x01:
880f095a1afSdan         case 0x02:
881f095a1afSdan           iMod = fuzzRandomInt(8) + 1;
882f095a1afSdan           break;
883f095a1afSdan 
884f095a1afSdan         case 0x03:                    /* text */
885f095a1afSdan         case 0x04: {                  /* blob */
886f095a1afSdan           int nByte;
887f095a1afSdan           int iFirst = 1 + fuzzGetVarint(&pChange->aSub[1], &nByte);
888f095a1afSdan           if( nByte>0 ){
889f095a1afSdan             iMod = fuzzRandomInt(nByte) + iFirst;
890f095a1afSdan           }
891f095a1afSdan           break;
892f095a1afSdan         }
893f095a1afSdan       }
894f095a1afSdan 
895f095a1afSdan       if( iMod>=0 ){
896f095a1afSdan         u8 mask = (1 << fuzzRandomInt(8 - (pChange->aSub[0]==0x03)));
897f095a1afSdan         pChange->aSub[iMod] ^= mask;
898f095a1afSdan       }
899f095a1afSdan     }
900f095a1afSdan   }
901f095a1afSdan 
902f095a1afSdan   return SQLITE_OK;
903f095a1afSdan }
904f095a1afSdan 
9055704f455Sdan /*
9065704f455Sdan ** Copy a single change from the input to the output changeset, making
9075704f455Sdan ** any modifications specified by (*pFuzz).
9085704f455Sdan */
fuzzCopyChange(FuzzChangeset * pParse,int iGrp,FuzzChange * pFuzz,u8 ** pp,u8 ** ppOut)909f095a1afSdan static int fuzzCopyChange(
910f095a1afSdan   FuzzChangeset *pParse,
911005d4c61Sdan   int iGrp,
912f095a1afSdan   FuzzChange *pFuzz,
913f095a1afSdan   u8 **pp, u8 **ppOut             /* IN/OUT: Input and output pointers */
914f095a1afSdan ){
9157844d215Sdan   int bPS = pParse->bPatchset;
916005d4c61Sdan   FuzzChangesetGroup *pGrp = pParse->apGroup[iGrp];
917f095a1afSdan   u8 *p = *pp;
918f095a1afSdan   u8 *pOut = *ppOut;
919f095a1afSdan   u8 eType = p++[0];
920f095a1afSdan   int iRec;
9217844d215Sdan   int nRec = ((eType==SQLITE_UPDATE && !bPS) ? 2 : 1);
922f095a1afSdan   int iUndef = -1;
923005d4c61Sdan   int nUpdate = 0;
924f095a1afSdan 
925f095a1afSdan   u8 eNew = eType;
926f095a1afSdan   if( pFuzz->iCurrent==pFuzz->iChange && pFuzz->eType==FUZZ_CHANGE_TYPE ){
927f095a1afSdan     switch( eType ){
928f095a1afSdan       case SQLITE_INSERT:
929f095a1afSdan         eNew = SQLITE_DELETE;
930f095a1afSdan         break;
931f095a1afSdan       case SQLITE_DELETE:
932f095a1afSdan         eNew = SQLITE_UPDATE;
933f095a1afSdan         break;
934f095a1afSdan       case SQLITE_UPDATE:
935f095a1afSdan         eNew = SQLITE_INSERT;
936f095a1afSdan         break;
937f095a1afSdan     }
938f095a1afSdan   }
939f095a1afSdan 
940f095a1afSdan   if( pFuzz->iCurrent==pFuzz->iChange
941f095a1afSdan    && pFuzz->eType==FUZZ_CHANGE_FIELD && eType==SQLITE_UPDATE
942f095a1afSdan   ){
943f095a1afSdan     int sz;
944f095a1afSdan     int i;
945f095a1afSdan     int nDef = 0;
946f095a1afSdan     u8 *pCsr = p+1;
947f095a1afSdan     for(i=0; i<pGrp->nCol; i++){
948f095a1afSdan       if( pCsr[0] && pGrp->aPK[i]==0 ) nDef++;
949f095a1afSdan       fuzzChangeSize(pCsr, &sz);
950f095a1afSdan       pCsr += sz;
951f095a1afSdan     }
952f095a1afSdan     if( nDef<=1 ) return -1;
953f095a1afSdan     nDef = fuzzRandomInt(nDef);
9547844d215Sdan     pCsr = p+1;
955f095a1afSdan     for(i=0; i<pGrp->nCol; i++){
956f095a1afSdan       if( pCsr[0] && pGrp->aPK[i]==0 ){
957f095a1afSdan         if( nDef==0 ) iUndef = i;
958f095a1afSdan         nDef--;
959f095a1afSdan       }
960f095a1afSdan       fuzzChangeSize(pCsr, &sz);
961f095a1afSdan       pCsr += sz;
962f095a1afSdan     }
963f095a1afSdan   }
964f095a1afSdan 
965005d4c61Sdan   /* Copy the change type and indirect flag. If the fuzz mode is
966005d4c61Sdan   ** FUZZ_CHANGE_INDIRECT, and the current change is the one selected for
967005d4c61Sdan   ** fuzzing, invert the indirect flag.  */
968f095a1afSdan   *(pOut++) = eNew;
969005d4c61Sdan   if( pFuzz->eType==FUZZ_CHANGE_INDIRECT && pFuzz->iCurrent==pFuzz->iChange ){
970005d4c61Sdan     *(pOut++) = !(*(p++));
971005d4c61Sdan   }else{
972f095a1afSdan     *(pOut++) = *(p++);
973005d4c61Sdan   }
974005d4c61Sdan 
975f095a1afSdan   for(iRec=0; iRec<nRec; iRec++){
976f095a1afSdan     int i;
9777844d215Sdan 
9787844d215Sdan     /* Copy the next record from the output to the input.
9797844d215Sdan     */
980f095a1afSdan     for(i=0; i<pGrp->nCol; i++){
981f095a1afSdan       int sz;
982f095a1afSdan       u8 *pCopy = p;
983f095a1afSdan 
9847844d215Sdan       /* If this is a patchset, and the input is a DELETE, then the only
9857844d215Sdan       ** fields present are the PK fields. So, if this is not a PK, skip to
9867844d215Sdan       ** the next column. If the current fuzz is FUZZ_CHANGE_TYPE, then
9877844d215Sdan       ** write a randomly selected value to the output.  */
9887844d215Sdan       if( bPS && eType==SQLITE_DELETE && pGrp->aPK[i]==0 ){
9897844d215Sdan         if( eType!=eNew ){
9907844d215Sdan           assert( eNew==SQLITE_UPDATE );
9917844d215Sdan           do {
9927844d215Sdan             pCopy = pParse->apVal[fuzzRandomInt(pParse->nVal)];
9937844d215Sdan           }while( pCopy[0]==0x00 );
9947844d215Sdan           fuzzChangeSize(pCopy, &sz);
9957844d215Sdan           memcpy(pOut, pCopy, sz);
9967844d215Sdan           pOut += sz;
9977844d215Sdan         }
9987844d215Sdan         continue;
9997844d215Sdan       }
10007844d215Sdan 
1001f095a1afSdan       if( p==pFuzz->pSub1 ){
1002f095a1afSdan         pCopy = pFuzz->pSub2;
1003f095a1afSdan       }else if( p==pFuzz->pSub2 ){
1004f095a1afSdan         pCopy = pFuzz->pSub1;
1005f095a1afSdan       }else if( i==iUndef ){
1006*4e2d3d40Smistachkin         pCopy = (u8*)"\0";
1007f095a1afSdan       }
1008f095a1afSdan 
1009f095a1afSdan       if( pCopy[0]==0x00 && eNew!=eType && eType==SQLITE_UPDATE && iRec==0 ){
1010f095a1afSdan         while( pCopy[0]==0x00 ){
1011005d4c61Sdan           pCopy = pParse->apVal[fuzzRandomInt(pParse->nVal)];
1012f095a1afSdan         }
1013f095a1afSdan       }else if( p[0]==0x00 && pCopy[0]!=0x00 ){
1014f095a1afSdan         return -1;
1015f095a1afSdan       }else{
1016f095a1afSdan         if( pGrp->aPK[i]>0 && pCopy[0]==0x05 ) return -1;
1017f095a1afSdan       }
1018f095a1afSdan 
10197844d215Sdan       if( (pFuzz->iGroup!=iGrp || i!=pFuzz->iDelete)
10207844d215Sdan        && (eNew==eType || eType!=SQLITE_UPDATE || iRec==0)
10217844d215Sdan        && (eNew==eType || eNew!=SQLITE_DELETE || !bPS || pGrp->aPK[i])
10227844d215Sdan       ){
1023f095a1afSdan         fuzzChangeSize(pCopy, &sz);
1024f095a1afSdan         memcpy(pOut, pCopy, sz);
1025f095a1afSdan         pOut += sz;
1026005d4c61Sdan         nUpdate += (pGrp->aPK[i]==0 && pCopy[0]!=0x00);
1027005d4c61Sdan       }
1028f095a1afSdan 
1029f095a1afSdan       fuzzChangeSize(p, &sz);
1030f095a1afSdan       p += sz;
1031f095a1afSdan     }
1032005d4c61Sdan 
1033005d4c61Sdan     if( iGrp==pFuzz->iGroup ){
1034005d4c61Sdan       if( pFuzz->eType==FUZZ_COLUMN_ADD ){
10357844d215Sdan         if( !bPS || eType!=SQLITE_DELETE ) *(pOut++) = 0x05;
1036005d4c61Sdan       }else if( pFuzz->eType==FUZZ_COLUMN_ADDPK ){
1037005d4c61Sdan         if( iRec==1 ){
1038005d4c61Sdan           *(pOut++) = 0x00;
1039005d4c61Sdan         }else{
1040005d4c61Sdan           u8 *pNew;
1041005d4c61Sdan           int szNew;
1042005d4c61Sdan           do {
1043005d4c61Sdan             pNew = pParse->apVal[fuzzRandomInt(pParse->nVal)];
1044005d4c61Sdan           }while( pNew[0]==0x00 || pNew[0]==0x05 );
1045005d4c61Sdan           fuzzChangeSize(pNew, &szNew);
1046005d4c61Sdan           memcpy(pOut, pNew, szNew);
1047005d4c61Sdan           pOut += szNew;
1048005d4c61Sdan         }
1049005d4c61Sdan       }
1050005d4c61Sdan     }
1051f095a1afSdan   }
1052f095a1afSdan 
1053f095a1afSdan   if( pFuzz->iCurrent==pFuzz->iChange ){
1054f095a1afSdan     if( pFuzz->eType==FUZZ_CHANGE_DUP ){
1055f095a1afSdan       int nByte = pOut - (*ppOut);
1056f095a1afSdan       memcpy(pOut, *ppOut, nByte);
1057f095a1afSdan       pOut += nByte;
1058f095a1afSdan     }
1059005d4c61Sdan 
1060f095a1afSdan     if( pFuzz->eType==FUZZ_CHANGE_DEL ){
1061f095a1afSdan       pOut = *ppOut;
1062f095a1afSdan     }
10637844d215Sdan     if( eNew!=eType && eNew==SQLITE_UPDATE && !bPS ){
1064f095a1afSdan       int i;
1065f095a1afSdan       u8 *pCsr = (*ppOut) + 2;
1066f095a1afSdan       for(i=0; i<pGrp->nCol; i++){
1067f095a1afSdan         int sz;
1068f095a1afSdan         u8 *pCopy = pCsr;
1069*4e2d3d40Smistachkin         if( pGrp->aPK[i] ) pCopy = (u8*)"\0";
1070f095a1afSdan         fuzzChangeSize(pCopy, &sz);
1071f095a1afSdan         memcpy(pOut, pCopy, sz);
1072f095a1afSdan         pOut += sz;
1073f095a1afSdan         fuzzChangeSize(pCsr, &sz);
1074f095a1afSdan         pCsr += sz;
1075f095a1afSdan       }
1076f095a1afSdan     }
1077f095a1afSdan   }
1078f095a1afSdan 
1079005d4c61Sdan   /* If a column is being deleted from this group, and this change was an
1080005d4c61Sdan   ** UPDATE, and there are now no non-PK, non-undefined columns in the
1081005d4c61Sdan   ** change, remove it altogether. */
1082005d4c61Sdan   if( pFuzz->eType==FUZZ_COLUMN_DEL && pFuzz->iGroup==iGrp
1083005d4c61Sdan    && eType==SQLITE_UPDATE && nUpdate==0
1084005d4c61Sdan   ){
1085005d4c61Sdan     pOut = *ppOut;
1086005d4c61Sdan   }
1087005d4c61Sdan 
1088f095a1afSdan   *pp = p;
1089f095a1afSdan   *ppOut = pOut;
1090f095a1afSdan   pFuzz->iCurrent += (eType==SQLITE_UPDATE || pFuzz->eType!=FUZZ_CHANGE_FIELD);
1091f095a1afSdan   return SQLITE_OK;
1092f095a1afSdan }
1093f095a1afSdan 
10945704f455Sdan /*
10955704f455Sdan ** Fuzz the changeset parsed into object pParse and write the results
10965704f455Sdan ** to file zOut on disk. Argument pBuf points to a buffer that is guaranteed
10975704f455Sdan ** to be large enough to hold the fuzzed changeset.
10985704f455Sdan **
10995704f455Sdan ** Return SQLITE_OK if successful, or an SQLite error code if an error occurs.
11005704f455Sdan */
fuzzDoOneFuzz(const char * zOut,u8 * pBuf,FuzzChangeset * pParse)1101f095a1afSdan static int fuzzDoOneFuzz(
1102f095a1afSdan   const char *zOut,               /* Filename to write modified changeset to */
1103f095a1afSdan   u8 *pBuf,                       /* Buffer to use for modified changeset */
1104f095a1afSdan   FuzzChangeset *pParse           /* Parse of input changeset */
1105f095a1afSdan ){
1106f095a1afSdan   FuzzChange change;
1107f095a1afSdan   int iGrp;
1108f095a1afSdan   int rc = -1;
1109f095a1afSdan 
1110f095a1afSdan   while( rc<0 ){
1111f095a1afSdan     u8 *pOut = pBuf;
1112f095a1afSdan     rc = fuzzSelectChange(pParse, &change);
1113f095a1afSdan     for(iGrp=0; rc==SQLITE_OK && iGrp<pParse->nGroup; iGrp++){
1114f095a1afSdan       FuzzChangesetGroup *pGrp = pParse->apGroup[iGrp];
1115f095a1afSdan       int nTab = strlen(pGrp->zTab) + 1;
1116005d4c61Sdan       int j;
1117005d4c61Sdan       int nRep = 1;
1118005d4c61Sdan 
1119005d4c61Sdan       /* If this is the group to delete for a FUZZ_GROUP_DEL change, jump to
1120005d4c61Sdan       ** the next group. Unless this is the only group in the changeset - in
1121005d4c61Sdan       ** that case this change cannot be applied.
1122005d4c61Sdan       **
1123005d4c61Sdan       ** Or, if this is a FUZZ_GROUP_DUP, set nRep to 2 to output two
1124005d4c61Sdan       ** copies of the group. */
1125005d4c61Sdan       if( change.iGroup==iGrp ){
1126005d4c61Sdan         if( change.eType==FUZZ_GROUP_DEL ){
1127005d4c61Sdan           if( pParse->nGroup==1 ) rc = -1;
1128005d4c61Sdan           continue;
1129005d4c61Sdan         }
1130005d4c61Sdan         else if( change.eType==FUZZ_GROUP_DUP ){
1131005d4c61Sdan           nRep = 2;
1132005d4c61Sdan         }
1133005d4c61Sdan       }
1134005d4c61Sdan 
1135005d4c61Sdan       for(j=0; j<nRep; j++){
1136f095a1afSdan         int i;
1137005d4c61Sdan         u8 *pSaved;
1138005d4c61Sdan         u8 *p = pGrp->aChange;
1139005d4c61Sdan         int nCol = pGrp->nCol;
1140005d4c61Sdan         int iPKDel = 0;
1141005d4c61Sdan         if( iGrp==change.iGroup ){
1142005d4c61Sdan           if( change.eType==FUZZ_COLUMN_ADD
1143005d4c61Sdan            || change.eType==FUZZ_COLUMN_ADDPK
1144005d4c61Sdan           ){
1145005d4c61Sdan             nCol++;
1146005d4c61Sdan           }else if( change.eType==FUZZ_COLUMN_DEL ){
1147005d4c61Sdan             nCol--;
1148005d4c61Sdan             iPKDel = pGrp->aPK[change.iDelete];
1149005d4c61Sdan           }
1150005d4c61Sdan         }
1151f095a1afSdan 
1152f095a1afSdan         /* Output a table header */
11537844d215Sdan         pOut++[0] = pParse->bPatchset ? 'P' : 'T';
1154005d4c61Sdan         pOut += fuzzPutVarint(pOut, nCol);
1155005d4c61Sdan 
1156005d4c61Sdan         for(i=0; i<pGrp->nCol; i++){
1157005d4c61Sdan           if( iGrp!=change.iGroup || i!=change.iDelete ){
1158005d4c61Sdan             u8 v = pGrp->aPK[i];
1159005d4c61Sdan             if( iPKDel && v>iPKDel ) v--;
1160005d4c61Sdan             *(pOut++) = v;
1161005d4c61Sdan           }
1162005d4c61Sdan         }
1163005d4c61Sdan         if( nCol>pGrp->nCol ){
1164005d4c61Sdan           if( change.eType==FUZZ_COLUMN_ADD ){
1165005d4c61Sdan             *(pOut++) = 0x00;
1166005d4c61Sdan           }else{
1167005d4c61Sdan             u8 max = 0;
1168005d4c61Sdan             for(i=0; i<pGrp->nCol; i++){
1169005d4c61Sdan               if( pGrp->aPK[i]>max ) max = pGrp->aPK[i];
1170005d4c61Sdan             }
1171005d4c61Sdan             *(pOut++) = max+1;
1172005d4c61Sdan           }
1173005d4c61Sdan         }
1174f095a1afSdan         memcpy(pOut, pGrp->zTab, nTab);
1175f095a1afSdan         pOut += nTab;
1176f095a1afSdan 
1177005d4c61Sdan         /* Output the change array. */
1178005d4c61Sdan         pSaved = pOut;
1179f095a1afSdan         for(i=0; rc==SQLITE_OK && i<pGrp->nChange; i++){
1180005d4c61Sdan           rc = fuzzCopyChange(pParse, iGrp, &change, &p, &pOut);
1181005d4c61Sdan         }
1182005d4c61Sdan         if( pOut==pSaved ) rc = -1;
1183f095a1afSdan       }
1184f095a1afSdan     }
1185f095a1afSdan     if( rc==SQLITE_OK ){
1186f095a1afSdan       fuzzWriteFile(zOut, pBuf, pOut-pBuf);
1187f095a1afSdan     }
1188f095a1afSdan   }
1189f095a1afSdan 
1190f095a1afSdan   return rc;
1191f095a1afSdan }
1192f095a1afSdan 
main(int argc,char ** argv)1193f095a1afSdan int main(int argc, char **argv){
1194f095a1afSdan   int nRepeat = 0;                /* Number of output files */
1195f095a1afSdan   int iSeed = 0;                  /* Value of PRNG seed */
1196f095a1afSdan   const char *zInput;             /* Name of input file */
1197f095a1afSdan   void *pChangeset = 0;           /* Input changeset */
1198f095a1afSdan   int nChangeset = 0;             /* Size of input changeset in bytes */
1199f095a1afSdan   int i;                          /* Current output file */
1200f095a1afSdan   FuzzChangeset changeset;        /* Partially parsed changeset */
1201f095a1afSdan   int rc;
1202f095a1afSdan   u8 *pBuf = 0;
1203f095a1afSdan 
1204f095a1afSdan   if( argc!=4 && argc!=2 ) usage(argv[0]);
1205f095a1afSdan   zInput = argv[1];
1206f095a1afSdan 
1207f095a1afSdan   fuzzReadFile(zInput, &nChangeset, &pChangeset);
1208f095a1afSdan   rc = fuzzParseChangeset(pChangeset, nChangeset, &changeset);
1209f095a1afSdan 
1210f095a1afSdan   if( rc==SQLITE_OK ){
1211f095a1afSdan     if( argc==2 ){
1212f095a1afSdan       for(i=0; i<changeset.nGroup; i++){
12137844d215Sdan         fuzzPrintGroup(&changeset, changeset.apGroup[i]);
1214f095a1afSdan       }
1215f095a1afSdan     }else{
12162d77d80aSdrh       pBuf = (u8*)fuzzMalloc((sqlite3_int64)nChangeset*2 + 1024);
1217f095a1afSdan       if( pBuf==0 ){
1218f095a1afSdan         rc = SQLITE_NOMEM;
1219f095a1afSdan       }else{
1220f095a1afSdan         iSeed = atoi(argv[2]);
1221f095a1afSdan         nRepeat = atoi(argv[3]);
1222f095a1afSdan         fuzzRandomSeed((unsigned int)iSeed);
1223f095a1afSdan         for(i=0; rc==SQLITE_OK && i<nRepeat; i++){
1224f095a1afSdan           char *zOut = sqlite3_mprintf("%s-%d", zInput, i);
1225005d4c61Sdan           rc = fuzzDoOneFuzz(zOut, pBuf, &changeset);
1226f095a1afSdan           sqlite3_free(zOut);
1227f095a1afSdan         }
1228f095a1afSdan         fuzzFree(pBuf);
1229f095a1afSdan       }
1230f095a1afSdan     }
1231f095a1afSdan   }
1232f095a1afSdan 
1233f095a1afSdan   if( rc!=SQLITE_OK ){
1234f095a1afSdan     fprintf(stderr, "error while processing changeset: %d\n", rc);
1235f095a1afSdan   }
1236005d4c61Sdan 
1237f095a1afSdan   return rc;
1238f095a1afSdan }
1239