xref: /sqlite-3.40.0/ext/session/changesetfuzz.c (revision 5704f455)
1 /*
2 ** 2018-11-01
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
7 **    May you do good and not evil.
8 **    May you find forgiveness for yourself and forgive others.
9 **    May you share freely, never taking more than you give.
10 **
11 *************************************************************************
12 ** This file contains code to implement the "changesetfuzz" command
13 ** line utility for fuzzing changeset blobs without corrupting them.
14 */
15 
16 
17 /************************************************************************
18 ** USAGE:
19 **
20 ** This program may be invoked in two ways:
21 **
22 **   changesetfuzz INPUT
23 **   changesetfuzz INPUT SEED N
24 **
25 ** Argument INPUT must be the name of a file containing a binary changeset.
26 ** In the first form above, this program outputs a human-readable version
27 ** of the same changeset. This is chiefly for debugging.
28 **
29 ** As well as changesets, this program can also dump and fuzz patchsets.
30 ** The term "changeset" is used for both patchsets and changesets from this
31 ** point on.
32 **
33 ** In the second form, arguments SEED and N must both be integers. In this
34 ** case, this program writes N binary changesets to disk. Each output
35 ** changeset is a slightly modified - "fuzzed" - version of the input.
36 ** The output changesets are written to files name "INPUT-$n", where $n is
37 ** an integer between 0 and N-1, inclusive. Output changesets are always
38 ** well-formed. Parameter SEED is used to seed the PRNG - any two
39 ** invocations of this program with the same SEED and input changeset create
40 ** the same N output changesets.
41 **
42 ** The ways in which an input changeset may be fuzzed are as follows:
43 **
44 **   1. Any two values within the changeset may be exchanged.
45 **
46 **   2. Any TEXT, BLOB, INTEGER or REAL value within the changeset
47 **      may have a single bit of its content flipped.
48 **
49 **   3. Any value within a changeset may be replaced by a pseudo-randomly
50 **      generated value.
51 **
52 ** The above operations never set a PRIMARY KEY column to NULL. Nor do they
53 ** set any value to "undefined", or replace any "undefined" value with
54 ** another. Any such operation risks producing a changeset that is not
55 ** well-formed.
56 **
57 **   4. A single change may be duplicated.
58 **
59 **   5. A single change may be removed, so long as this does not mean that
60 **      there are zero changes following a table-header within the changeset.
61 **
62 **   6. A single change may have its type (INSERT, DELETE, UPDATE) changed.
63 **      If an INSERT is changed to a DELETE (or vice versa), the type is
64 **      simply changed - no other modifications are required. If an INSERT
65 **      or DELETE is changed to an UPDATE, then the single record is duplicated
66 **      (as both the old.* and new.* records of the new UPDATE change). If an
67 **      UPDATE is changed to a DELETE or INSERT, the new.* record is discarded
68 **      and any "undefined" fields replaced with pseudo-randomly generated
69 **      values.
70 **
71 **   7. An UPDATE change that modifies N table columns may be modified so
72 **      that it updates N-1 columns, so long as (N>1).
73 **
74 **   8. The "indirect" flag may be toggled for any change.
75 **
76 ** Entire group of changes may also be operated on:
77 **
78 **   9. Duplicate an existing group.
79 **
80 **  10. Remove an existing group.
81 **
82 **  11. The positions of two groups may be exchanged.
83 **
84 ** There are also schema changes:
85 **
86 **  12. A non-PK column may be added to a table. In this case a NULL
87 **      value is appended to all records.
88 **
89 **  13. A PK column may be added to a table. In this case a non-NULL
90 **      value is appended to all INSERT, DELETE and UPDATE old.* records.
91 **      An "undefined" is appended to new.* UPDATE records.
92 **
93 **  14. A column may be removed from a table, provided that it is not the
94 **      only PRIMARY KEY column in the table. In this case the corresponding
95 **      field is removed from all records. In cases where this leaves an UPDATE
96 **      with no non-PK, non-undefined fields, the entire change is removed.
97 */
98 
99 #include "sqlite3.h"
100 #include <stdio.h>
101 #include <stdlib.h>
102 #include <string.h>
103 #include <assert.h>
104 #include <ctype.h>
105 
106 #define FUZZ_VALUE_SUB       1    /* Replace one value with a copy of another */
107 #define FUZZ_VALUE_MOD       2    /* Modify content by 1 bit */
108 #define FUZZ_VALUE_RND       3    /* Replace with pseudo-random value */
109 
110 #define FUZZ_CHANGE_DUP      4    /* Duplicate an existing change */
111 #define FUZZ_CHANGE_DEL      5    /* Completely remove one change */
112 #define FUZZ_CHANGE_TYPE     6    /* Change the type of one change */
113 #define FUZZ_CHANGE_FIELD    7    /* Change an UPDATE to modify fewer columns */
114 #define FUZZ_CHANGE_INDIRECT 8    /* Toggle the "indirect" flag of a change */
115 
116 #define FUZZ_GROUP_DUP       9    /* Duplicate a change group */
117 #define FUZZ_GROUP_DEL      10    /* Delete an entire change group */
118 #define FUZZ_GROUP_SWAP     11    /* Exchange the position of two groups */
119 
120 #define FUZZ_COLUMN_ADD     12     /* Add column to table definition */
121 #define FUZZ_COLUMN_ADDPK   13     /* Add PK column to table definition */
122 #define FUZZ_COLUMN_DEL     14     /* Remove column from table definition */
123 
124 
125 
126 typedef unsigned char u8;
127 typedef sqlite3_uint64 u64;
128 typedef sqlite3_int64 i64;
129 typedef unsigned int u32;
130 
131 /*
132 ** Show a usage message on stderr then quit.
133 */
134 static void usage(const char *argv0){
135   fprintf(stderr, "Usage: %s FILENAME ?SEED N?\n", argv0);
136   exit(1);
137 }
138 
139 /*
140 ** Read the content of a disk file into an in-memory buffer
141 */
142 static void fuzzReadFile(const char *zFilename, int *pSz, void **ppBuf){
143   FILE *f;
144   int sz;
145   void *pBuf;
146   f = fopen(zFilename, "rb");
147   if( f==0 ){
148     fprintf(stderr, "cannot open \"%s\" for reading\n", zFilename);
149     exit(1);
150   }
151   fseek(f, 0, SEEK_END);
152   sz = (int)ftell(f);
153   rewind(f);
154   pBuf = sqlite3_malloc( sz ? sz : 1 );
155   if( pBuf==0 ){
156     fprintf(stderr, "cannot allocate %d to hold content of \"%s\"\n",
157             sz, zFilename);
158     exit(1);
159   }
160   if( sz>0 ){
161     if( fread(pBuf, sz, 1, f)!=1 ){
162       fprintf(stderr, "cannot read all %d bytes of \"%s\"\n", sz, zFilename);
163       exit(1);
164     }
165     fclose(f);
166   }
167   *pSz = sz;
168   *ppBuf = pBuf;
169 }
170 
171 /*
172 ** Write the contents of buffer pBuf, size nBuf bytes, into file zFilename
173 ** on disk. zFilename, if it already exists, is clobbered.
174 */
175 static void fuzzWriteFile(const char *zFilename, void *pBuf, int nBuf){
176   FILE *f;
177   f = fopen(zFilename, "wb");
178   if( f==0 ){
179     fprintf(stderr, "cannot open \"%s\" for writing\n", zFilename);
180     exit(1);
181   }
182   if( fwrite(pBuf, nBuf, 1, f)!=1 ){
183     fprintf(stderr, "cannot write to \"%s\"\n", zFilename);
184     exit(1);
185   }
186   fclose(f);
187 }
188 
189 static int fuzzCorrupt(){
190   return SQLITE_CORRUPT;
191 }
192 
193 /*************************************************************************
194 ** The following block is a copy of the implementation of SQLite function
195 ** sqlite3_randomness. This version has two important differences:
196 **
197 **   1. It always uses the same seed. So the sequence of random data output
198 **      is the same for every run of the program.
199 **
200 **   2. It is not threadsafe.
201 */
202 static struct sqlite3PrngType {
203   unsigned char i, j;             /* State variables */
204   unsigned char s[256];           /* State variables */
205 } sqlite3Prng = {
206     0xAF, 0x28,
207   {
208     0x71, 0xF5, 0xB4, 0x6E, 0x80, 0xAB, 0x1D, 0xB8,
209     0xFB, 0xB7, 0x49, 0xBF, 0xFF, 0x72, 0x2D, 0x14,
210     0x79, 0x09, 0xE3, 0x78, 0x76, 0xB0, 0x2C, 0x0A,
211     0x8E, 0x23, 0xEE, 0xDF, 0xE0, 0x9A, 0x2F, 0x67,
212     0xE1, 0xBE, 0x0E, 0xA7, 0x08, 0x97, 0xEB, 0x77,
213     0x78, 0xBA, 0x9D, 0xCA, 0x49, 0x4C, 0x60, 0x9A,
214     0xF6, 0xBD, 0xDA, 0x7F, 0xBC, 0x48, 0x58, 0x52,
215     0xE5, 0xCD, 0x83, 0x72, 0x23, 0x52, 0xFF, 0x6D,
216     0xEF, 0x0F, 0x82, 0x29, 0xA0, 0x83, 0x3F, 0x7D,
217     0xA4, 0x88, 0x31, 0xE7, 0x88, 0x92, 0x3B, 0x9B,
218     0x3B, 0x2C, 0xC2, 0x4C, 0x71, 0xA2, 0xB0, 0xEA,
219     0x36, 0xD0, 0x00, 0xF1, 0xD3, 0x39, 0x17, 0x5D,
220     0x2A, 0x7A, 0xE4, 0xAD, 0xE1, 0x64, 0xCE, 0x0F,
221     0x9C, 0xD9, 0xF5, 0xED, 0xB0, 0x22, 0x5E, 0x62,
222     0x97, 0x02, 0xA3, 0x8C, 0x67, 0x80, 0xFC, 0x88,
223     0x14, 0x0B, 0x15, 0x10, 0x0F, 0xC7, 0x40, 0xD4,
224     0xF1, 0xF9, 0x0E, 0x1A, 0xCE, 0xB9, 0x1E, 0xA1,
225     0x72, 0x8E, 0xD7, 0x78, 0x39, 0xCD, 0xF4, 0x5D,
226     0x2A, 0x59, 0x26, 0x34, 0xF2, 0x73, 0x0B, 0xA0,
227     0x02, 0x51, 0x2C, 0x03, 0xA3, 0xA7, 0x43, 0x13,
228     0xE8, 0x98, 0x2B, 0xD2, 0x53, 0xF8, 0xEE, 0x91,
229     0x7D, 0xE7, 0xE3, 0xDA, 0xD5, 0xBB, 0xC0, 0x92,
230     0x9D, 0x98, 0x01, 0x2C, 0xF9, 0xB9, 0xA0, 0xEB,
231     0xCF, 0x32, 0xFA, 0x01, 0x49, 0xA5, 0x1D, 0x9A,
232     0x76, 0x86, 0x3F, 0x40, 0xD4, 0x89, 0x8F, 0x9C,
233     0xE2, 0xE3, 0x11, 0x31, 0x37, 0xB2, 0x49, 0x28,
234     0x35, 0xC0, 0x99, 0xB6, 0xD0, 0xBC, 0x66, 0x35,
235     0xF7, 0x83, 0x5B, 0xD7, 0x37, 0x1A, 0x2B, 0x18,
236     0xA6, 0xFF, 0x8D, 0x7C, 0x81, 0xA8, 0xFC, 0x9E,
237     0xC4, 0xEC, 0x80, 0xD0, 0x98, 0xA7, 0x76, 0xCC,
238     0x9C, 0x2F, 0x7B, 0xFF, 0x8E, 0x0E, 0xBB, 0x90,
239     0xAE, 0x13, 0x06, 0xF5, 0x1C, 0x4E, 0x52, 0xF7
240   }
241 };
242 
243 /*
244 ** Generate and return single random byte
245 */
246 static unsigned char fuzzRandomByte(void){
247   unsigned char t;
248   sqlite3Prng.i++;
249   t = sqlite3Prng.s[sqlite3Prng.i];
250   sqlite3Prng.j += t;
251   sqlite3Prng.s[sqlite3Prng.i] = sqlite3Prng.s[sqlite3Prng.j];
252   sqlite3Prng.s[sqlite3Prng.j] = t;
253   t += sqlite3Prng.s[sqlite3Prng.i];
254   return sqlite3Prng.s[t];
255 }
256 
257 /*
258 ** Return N random bytes.
259 */
260 static void fuzzRandomBlob(int nBuf, unsigned char *zBuf){
261   int i;
262   for(i=0; i<nBuf; i++){
263     zBuf[i] = fuzzRandomByte();
264   }
265 }
266 
267 /*
268 ** Return a random integer between 0 and nRange (not inclusive).
269 */
270 static unsigned int fuzzRandomInt(unsigned int nRange){
271   unsigned int ret;
272   assert( nRange>0 );
273   fuzzRandomBlob(sizeof(ret), (unsigned char*)&ret);
274   return (ret % nRange);
275 }
276 
277 static u64 fuzzRandomU64(){
278   u64 ret;
279   fuzzRandomBlob(sizeof(ret), (unsigned char*)&ret);
280   return ret;
281 }
282 
283 static void fuzzRandomSeed(unsigned int iSeed){
284   int i;
285   for(i=0; i<256; i+=4){
286     sqlite3Prng.s[i] ^= ((iSeed >> 24) & 0xFF);
287     sqlite3Prng.s[i+1] ^= ((iSeed >> 16) & 0xFF);
288     sqlite3Prng.s[i+2] ^= ((iSeed >>  8) & 0xFF);
289     sqlite3Prng.s[i+3] ^= ((iSeed >>  0) & 0xFF);
290   }
291 }
292 /*
293 ** End of code for generating pseudo-random values.
294 *************************************************************************/
295 
296 typedef struct FuzzChangeset FuzzChangeset;
297 typedef struct FuzzChangesetGroup FuzzChangesetGroup;
298 typedef struct FuzzChange FuzzChange;
299 
300 /*
301 ** Object containing partially parsed changeset.
302 */
303 struct FuzzChangeset {
304   int bPatchset;                  /* True for a patchset */
305   FuzzChangesetGroup **apGroup;   /* Array of groups in changeset */
306   int nGroup;                     /* Number of items in list pGroup */
307   u8 **apVal;                     /* Array of all values in changeset */
308   int nVal;                       /* Number of used slots in apVal[] */
309   int nChange;                    /* Number of changes in changeset */
310   int nUpdate;                    /* Number of UPDATE changes in changeset */
311 };
312 
313 /*
314 ** There is one object of this type for each change-group (table header)
315 ** in the input changeset.
316 */
317 struct FuzzChangesetGroup {
318   const char *zTab;               /* Name of table */
319   int nCol;                       /* Number of columns in table */
320   u8 *aPK;                        /* PK array for this table */
321   u8 *aChange;                    /* Buffer containing array of changes */
322   int szChange;                   /* Size of buffer aChange[] in bytes */
323   int nChange;                    /* Number of changes in buffer aChange[] */
324 };
325 
326 /*
327 ** Description of a fuzz change to be applied to a changeset.
328 */
329 struct FuzzChange {
330   int eType;                      /* One of the FUZZ_* constants above */
331   int iChange;                    /* Change or UPDATE to modify */
332   int iGroup;                     /* Group to modify */
333   int iDelete;                    /* Field to remove (FUZZ_COLUMN_DEL) */
334   u8 *pSub1;                      /* Replace this value with pSub2 */
335   u8 *pSub2;                      /* And this one with pSub1 */
336   u8 aSub[128];                   /* Buffer for substitute value */
337   int iCurrent;                   /* Current change number */
338 };
339 
340 /*
341 ** Allocate and return nByte bytes of zeroed memory.
342 */
343 static void *fuzzMalloc(int nByte){
344   void *pRet = sqlite3_malloc(nByte);
345   if( pRet ){
346     memset(pRet, 0, nByte);
347   }
348   return pRet;
349 }
350 
351 /*
352 ** Free the buffer indicated by the first argument. This function is used
353 ** to free buffers allocated by fuzzMalloc().
354 */
355 static void fuzzFree(void *p){
356   sqlite3_free(p);
357 }
358 
359 /*
360 ** Argument p points to a buffer containing an SQLite varint that, assuming the
361 ** input is not corrupt, may be between 0 and 0x7FFFFFFF, inclusive. Before
362 ** returning, this function sets (*pnVal) to the value of that varint, and
363 ** returns the number of bytes of space that it takes up.
364 */
365 static int fuzzGetVarint(u8 *p, int *pnVal){
366   int i;
367   sqlite3_uint64 nVal = 0;
368   for(i=0; i<9; i++){
369     nVal = (nVal<<7) + (p[i] & 0x7F);
370     if( (p[i] & 0x80)==0 ){
371       i++;
372       break;
373     }
374   }
375   *pnVal = (int)nVal;
376   return i;
377 }
378 
379 /*
380 ** Write value nVal into the buffer indicated by argument p as an SQLite
381 ** varint. nVal is guaranteed to be between 0 and (2^21-1), inclusive.
382 ** Return the number of bytes written to buffer p.
383 */
384 static int fuzzPutVarint(u8 *p, int nVal){
385   assert( nVal>0 && nVal<2097152 );
386   if( nVal<128 ){
387     p[0] = nVal;
388     return 1;
389   }
390   if( nVal<16384 ){
391     p[0] = ((nVal >> 7) & 0x7F) | 0x80;
392     p[1] = (nVal & 0x7F);
393     return 2;
394   }
395 
396   p[0] = ((nVal >> 14) & 0x7F) | 0x80;
397   p[1] = ((nVal >> 7) & 0x7F) | 0x80;
398   p[2] = (nVal & 0x7F);
399   return 3;
400 }
401 
402 /*
403 ** Read a 64-bit big-endian integer value from buffer aRec[]. Return
404 ** the value read.
405 */
406 static i64 fuzzGetI64(u8 *aRec){
407   return (i64)(
408       (((u64)aRec[0]) << 56)
409     + (((u64)aRec[1]) << 48)
410     + (((u64)aRec[2]) << 40)
411     + (((u64)aRec[3]) << 32)
412     + (((u64)aRec[4]) << 24)
413     + (((u64)aRec[5]) << 16)
414     + (((u64)aRec[6]) <<  8)
415     + (((u64)aRec[7]) <<  0)
416   );
417 }
418 
419 /*
420 ** Write value iVal to buffer aRec[] as an unsigned 64-bit big-endian integer.
421 */
422 static void fuzzPutU64(u8 *aRec, u64 iVal){
423   aRec[0] = (iVal>>56) & 0xFF;
424   aRec[1] = (iVal>>48) & 0xFF;
425   aRec[2] = (iVal>>40) & 0xFF;
426   aRec[3] = (iVal>>32) & 0xFF;
427   aRec[4] = (iVal>>24) & 0xFF;
428   aRec[5] = (iVal>>16) & 0xFF;
429   aRec[6] = (iVal>> 8) & 0xFF;
430   aRec[7] = (iVal)     & 0xFF;
431 }
432 
433 /*
434 ** Parse a single table-header from the input. Allocate a new change-group
435 ** object with the results. Return SQLITE_OK if successful, or an error code
436 ** otherwise.
437 */
438 static int fuzzParseHeader(
439   FuzzChangeset *pParse,          /* Changeset parse object */
440   u8 **ppHdr,                     /* IN/OUT: Iterator */
441   u8 *pEnd,                       /* 1 byte past EOF */
442   FuzzChangesetGroup **ppGrp      /* OUT: New change-group object */
443 ){
444   int rc = SQLITE_OK;
445   FuzzChangesetGroup *pGrp;
446   u8 cHdr = (pParse->bPatchset ? 'P' : 'T');
447 
448   assert( pEnd>(*ppHdr) );
449   pGrp = (FuzzChangesetGroup*)fuzzMalloc(sizeof(FuzzChangesetGroup));
450   if( !pGrp ){
451     rc = SQLITE_NOMEM;
452   }else{
453     u8 *p = *ppHdr;
454     if( p[0]!=cHdr ){
455       rc = fuzzCorrupt();
456     }else{
457       p++;
458       p += fuzzGetVarint(p, &pGrp->nCol);
459       pGrp->aPK = p;
460       p += pGrp->nCol;
461       pGrp->zTab = (const char*)p;
462       p = &p[strlen(p)+1];
463 
464       if( p>=pEnd ){
465         rc = fuzzCorrupt();
466       }
467     }
468     *ppHdr = p;
469   }
470 
471   if( rc!=SQLITE_OK ){
472     fuzzFree(pGrp);
473     pGrp = 0;
474   }
475 
476   *ppGrp = pGrp;
477   return rc;
478 }
479 
480 /*
481 ** Argument p points to a buffer containing a single changeset-record value.
482 ** This function attempts to determine the size of the value in bytes. If
483 ** successful, it sets (*pSz) to the size and returns SQLITE_OK. Or, if the
484 ** buffer does not contain a valid value, SQLITE_CORRUPT is returned and
485 ** the final value of (*pSz) is undefined.
486 */
487 static int fuzzChangeSize(u8 *p, int *pSz){
488   u8 eType = p[0];
489   switch( eType ){
490     case 0x00:                    /* undefined */
491     case 0x05:                    /* null */
492       *pSz = 1;
493       break;
494 
495     case 0x01:                    /* integer */
496     case 0x02:                    /* real */
497       *pSz = 9;
498       break;
499 
500     case 0x03:                    /* text */
501     case 0x04: {                  /* blob */
502       int nTxt;
503       int sz;
504       sz = fuzzGetVarint(&p[1], &nTxt);
505       *pSz = 1 + sz + nTxt;
506       break;
507     }
508 
509     default:
510       return fuzzCorrupt();
511   }
512   return SQLITE_OK;
513 }
514 
515 /*
516 ** When this function is called, (*ppRec) points to the start of a
517 ** record in a changeset being parsed. This function adds entries
518 ** to the pParse->apVal[] array for all values and advances (*ppRec)
519 ** to one byte past the end of the record. Argument pEnd points to
520 ** one byte past the end of the input changeset.
521 **
522 ** Argument bPkOnly is true if the record being parsed is part of
523 ** a DELETE record in a patchset. In this case, all non-primary-key
524 ** fields have been omitted from the record.
525 **
526 ** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
527 */
528 static int fuzzParseRecord(
529   u8 **ppRec,                     /* IN/OUT: Iterator */
530   u8 *pEnd,                       /* One byte after end of input data */
531   FuzzChangeset *pParse,          /* Changeset parse context */
532   int bPkOnly                     /* True if non-PK fields omitted */
533 ){
534   int rc = SQLITE_OK;
535   FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1];
536   int i;
537   u8 *p = *ppRec;
538 
539   for(i=0; rc==SQLITE_OK && i<pGrp->nCol && p<pEnd; i++){
540     if( bPkOnly==0 || pGrp->aPK[i] ){
541       int sz;
542       if( (pParse->nVal & (pParse->nVal-1))==0 ){
543         int nNew = pParse->nVal ? pParse->nVal*2 : 4;
544         u8 **apNew = (u8**)sqlite3_realloc(pParse->apVal, nNew*sizeof(u8*));
545         if( apNew==0 ) return SQLITE_NOMEM;
546         pParse->apVal = apNew;
547       }
548       pParse->apVal[pParse->nVal++] = p;
549       rc = fuzzChangeSize(p, &sz);
550       p += sz;
551     }
552   }
553 
554   if( rc==SQLITE_OK && i<pGrp->nCol ){
555     rc = fuzzCorrupt();
556   }
557 
558   *ppRec = p;
559   return rc;
560 }
561 
562 /*
563 ** Parse the array of changes starting at (*ppData) and add entries for
564 ** all values to the pParse->apVal[] array. Argument pEnd points to one byte
565 ** past the end of the input changeset. If successful, set (*ppData) to point
566 ** to one byte past the end of the change array and return SQLITE_OK.
567 ** Otherwise, return an SQLite error code. The final value of (*ppData) is
568 ** undefined in this case.
569 */
570 static int fuzzParseChanges(u8 **ppData, u8 *pEnd, FuzzChangeset *pParse){
571   u8 cHdr = (pParse->bPatchset ? 'P' : 'T');
572   FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1];
573   int rc = SQLITE_OK;
574   u8 *p = *ppData;
575 
576   pGrp->aChange = p;
577   while( rc==SQLITE_OK && p<pEnd && p[0]!=cHdr ){
578     u8 eOp = p[0];
579     u8 bIndirect = p[1];
580 
581     p += 2;
582     if( eOp==SQLITE_UPDATE ){
583       pParse->nUpdate++;
584       if( pParse->bPatchset==0 ){
585         rc = fuzzParseRecord(&p, pEnd, pParse, 0);
586       }
587     }else if( eOp!=SQLITE_INSERT && eOp!=SQLITE_DELETE ){
588       rc = fuzzCorrupt();
589     }
590     if( rc==SQLITE_OK ){
591       int bPkOnly = (eOp==SQLITE_DELETE && pParse->bPatchset);
592       rc = fuzzParseRecord(&p, pEnd, pParse, bPkOnly);
593     }
594     pGrp->nChange++;
595     pParse->nChange++;
596   }
597   pGrp->szChange = p - pGrp->aChange;
598 
599   *ppData = p;
600   return rc;
601 }
602 
603 /*
604 ** Parse the changeset stored in buffer pChangeset (nChangeset bytes in
605 ** size). If successful, write the results into (*pParse) and return
606 ** SQLITE_OK. Or, if an error occurs, return an SQLite error code. The
607 ** final state of (*pParse) is undefined in this case.
608 */
609 static int fuzzParseChangeset(
610   u8 *pChangeset,                 /* Buffer containing changeset */
611   int nChangeset,                 /* Size of buffer in bytes */
612   FuzzChangeset *pParse           /* OUT: Results of parse */
613 ){
614   u8 *pEnd = &pChangeset[nChangeset];
615   u8 *p = pChangeset;
616   int rc = SQLITE_OK;
617 
618   memset(pParse, 0, sizeof(FuzzChangeset));
619   if( nChangeset>0 ){
620     pParse->bPatchset = (pChangeset[0]=='P');
621   }
622 
623   while( rc==SQLITE_OK && p<pEnd ){
624     FuzzChangesetGroup *pGrp = 0;
625 
626     /* Read a table-header from the changeset */
627     rc = fuzzParseHeader(pParse, &p, pEnd, &pGrp);
628     assert( (rc==SQLITE_OK)==(pGrp!=0) );
629 
630     /* If the table-header was successfully parsed, add the new change-group
631     ** to the array and parse the associated changes. */
632     if( rc==SQLITE_OK ){
633       FuzzChangesetGroup **apNew = (FuzzChangesetGroup**)sqlite3_realloc(
634           pParse->apGroup, sizeof(FuzzChangesetGroup*)*(pParse->nGroup+1)
635       );
636       if( apNew==0 ){
637         rc = SQLITE_NOMEM;
638       }else{
639         apNew[pParse->nGroup] = pGrp;
640         pParse->apGroup = apNew;
641         pParse->nGroup++;
642       }
643       rc = fuzzParseChanges(&p, pEnd, pParse);
644     }
645   }
646 
647   return rc;
648 }
649 
650 /*
651 ** When this function is called, (*ppRec) points to the first byte of
652 ** a record that is part of change-group pGrp. This function attempts
653 ** to output a human-readable version of the record to stdout and advance
654 ** (*ppRec) to point to the first byte past the end of the record before
655 ** returning. If successful, SQLITE_OK is returned. Otherwise, an SQLite
656 ** error code.
657 **
658 ** If parameter bPkOnly is non-zero, then all non-primary-key fields have
659 ** been omitted from the record. This occurs for records that are part
660 ** of DELETE changes in patchsets.
661 */
662 static int fuzzPrintRecord(FuzzChangesetGroup *pGrp, u8 **ppRec, int bPKOnly){
663   int rc = SQLITE_OK;
664   u8 *p = *ppRec;
665   int i;
666   const char *zPre = " (";
667 
668   for(i=0; i<pGrp->nCol; i++){
669     if( bPKOnly==0 || pGrp->aPK[i] ){
670       u8 eType = p++[0];
671       switch( eType ){
672         case 0x00:                    /* undefined */
673           printf("%sn/a", zPre);
674           break;
675 
676         case 0x01: {                  /* integer */
677           sqlite3_int64 iVal = 0;
678           iVal = fuzzGetI64(p);
679           printf("%s%lld", zPre, iVal);
680           p += 8;
681           break;
682         }
683 
684         case 0x02: {                  /* real */
685           sqlite3_int64 iVal = 0;
686           double fVal = 0.0;
687           iVal = fuzzGetI64(p);
688           memcpy(&fVal, &iVal, 8);
689           printf("%s%f", zPre, fVal);
690           p += 8;
691           break;
692         }
693 
694         case 0x03:                    /* text */
695         case 0x04: {                  /* blob */
696           int nTxt;
697           int sz;
698           int i;
699           p += fuzzGetVarint(p, &nTxt);
700           printf("%s%s", zPre, eType==0x03 ? "'" : "X'");
701           for(i=0; i<nTxt; i++){
702             if( eType==0x03 ){
703               printf("%c", p[i]);
704             }else{
705               char aHex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
706                                '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
707               };
708               printf("%c", aHex[ p[i]>>4 ]);
709               printf("%c", aHex[ p[i] & 0x0F ]);
710             }
711           }
712           printf("'");
713           p += nTxt;
714           break;
715         }
716 
717         case 0x05:                    /* null */
718           printf("%sNULL", zPre);
719           break;
720       }
721       zPre = ", ";
722     }
723   }
724   printf(")");
725 
726   *ppRec = p;
727   return rc;
728 }
729 
730 /*
731 ** Print a human-readable version of the table-header and all changes in the
732 ** change-group passed as the second argument.
733 */
734 static void fuzzPrintGroup(FuzzChangeset *pParse, FuzzChangesetGroup *pGrp){
735   int i;
736   u8 *p;
737 
738   /* The table header */
739   printf("TABLE:  %s nCol=%d aPK=", pGrp->zTab, pGrp->nCol);
740   for(i=0; i<pGrp->nCol; i++){
741     printf("%d", (int)pGrp->aPK[i]);
742   }
743   printf("\n");
744 
745   /* The array of changes */
746   p = pGrp->aChange;
747   for(i=0; i<pGrp->nChange; i++){
748     u8 eType = p[0];
749     u8 bIndirect = p[1];
750     printf("%s (ind=%d):",
751         (eType==SQLITE_INSERT) ? "INSERT" :
752         (eType==SQLITE_DELETE ? "DELETE" : "UPDATE"),
753         bIndirect
754     );
755     p += 2;
756 
757     if( pParse->bPatchset==0 && eType==SQLITE_UPDATE ){
758       fuzzPrintRecord(pGrp, &p, 0);
759     }
760     fuzzPrintRecord(pGrp, &p, eType==SQLITE_DELETE && pParse->bPatchset);
761     printf("\n");
762   }
763 }
764 
765 /*
766 ** Initialize the object passed as the second parameter with details
767 ** of the change that will be attempted (type of change, to which part of the
768 ** changeset it applies etc.). If successful, return SQLITE_OK. Or, if an
769 ** error occurs, return an SQLite error code.
770 **
771 ** If a negative value is returned, then the selected change would have
772 ** produced a non-well-formed changeset. In this case the caller should
773 ** call this function again.
774 */
775 static int fuzzSelectChange(FuzzChangeset *pParse, FuzzChange *pChange){
776   int iSub;
777 
778   memset(pChange, 0, sizeof(FuzzChange));
779   pChange->eType = fuzzRandomInt(FUZZ_COLUMN_DEL) + 1;
780 
781   assert( pChange->eType==FUZZ_VALUE_SUB
782        || pChange->eType==FUZZ_VALUE_MOD
783        || pChange->eType==FUZZ_VALUE_RND
784        || pChange->eType==FUZZ_CHANGE_DUP
785        || pChange->eType==FUZZ_CHANGE_DEL
786        || pChange->eType==FUZZ_CHANGE_TYPE
787        || pChange->eType==FUZZ_CHANGE_FIELD
788        || pChange->eType==FUZZ_CHANGE_INDIRECT
789        || pChange->eType==FUZZ_GROUP_DUP
790        || pChange->eType==FUZZ_GROUP_DEL
791        || pChange->eType==FUZZ_GROUP_SWAP
792        || pChange->eType==FUZZ_COLUMN_ADD
793        || pChange->eType==FUZZ_COLUMN_ADDPK
794        || pChange->eType==FUZZ_COLUMN_DEL
795   );
796 
797   pChange->iGroup = fuzzRandomInt(pParse->nGroup);
798   pChange->iChange = fuzzRandomInt(pParse->nChange);
799   if( pChange->eType==FUZZ_CHANGE_FIELD ){
800     if( pParse->nUpdate==0 ) return -1;
801     pChange->iChange = fuzzRandomInt(pParse->nUpdate);
802   }
803 
804   pChange->iDelete = -1;
805   if( pChange->eType==FUZZ_COLUMN_DEL ){
806     FuzzChangesetGroup *pGrp = pParse->apGroup[pChange->iGroup];
807     int i;
808     pChange->iDelete = fuzzRandomInt(pGrp->nCol);
809     for(i=pGrp->nCol-1; i>=0; i--){
810       if( pGrp->aPK[i] && pChange->iDelete!=i ) break;
811     }
812     if( i<0 ) return -1;
813   }
814 
815   if( pChange->eType==FUZZ_GROUP_SWAP ){
816     FuzzChangesetGroup *pGrp;
817     int iGrp = pChange->iGroup;
818     if( pParse->nGroup==1 ) return -1;
819     while( iGrp==pChange->iGroup ){
820       iGrp = fuzzRandomInt(pParse->nGroup);
821     }
822     pGrp = pParse->apGroup[pChange->iGroup];
823     pParse->apGroup[pChange->iGroup] = pParse->apGroup[iGrp];
824     pParse->apGroup[iGrp] = pGrp;
825   }
826 
827   if( pChange->eType==FUZZ_VALUE_SUB
828    || pChange->eType==FUZZ_VALUE_MOD
829    || pChange->eType==FUZZ_VALUE_RND
830   ){
831     iSub = fuzzRandomInt(pParse->nVal);
832     pChange->pSub1 = pParse->apVal[iSub];
833     if( pChange->eType==FUZZ_VALUE_SUB ){
834       iSub = fuzzRandomInt(pParse->nVal);
835       pChange->pSub2 = pParse->apVal[iSub];
836     }else{
837       pChange->pSub2 = pChange->aSub;
838     }
839 
840     if( pChange->eType==FUZZ_VALUE_RND ){
841       pChange->aSub[0] = (u8)(fuzzRandomInt(5) + 1);
842       switch( pChange->aSub[0] ){
843         case 0x01: {                  /* integer */
844           u64 iVal = fuzzRandomU64();
845           fuzzPutU64(&pChange->aSub[1], iVal);
846           break;
847         }
848 
849         case 0x02: {                  /* real */
850           u64 iVal1 = fuzzRandomU64();
851           u64 iVal2 = fuzzRandomU64();
852           double d = (double)iVal1 / (double)iVal2;
853           memcpy(&iVal1, &d, sizeof(iVal1));
854           fuzzPutU64(&pChange->aSub[1], iVal1);
855           break;
856         }
857 
858         case 0x03:                    /* text */
859         case 0x04: {                  /* blob */
860           int nByte = fuzzRandomInt(48);
861           pChange->aSub[1] = nByte;
862           fuzzRandomBlob(nByte, &pChange->aSub[2]);
863           if( pChange->aSub[0]==0x03 ){
864             int i;
865             for(i=0; i<nByte; i++){
866               pChange->aSub[2+i] &= 0x7F;
867             }
868           }
869           break;
870         }
871       }
872     }
873     if( pChange->eType==FUZZ_VALUE_MOD ){
874       int sz;
875       int iMod = -1;
876       fuzzChangeSize(pChange->pSub1, &sz);
877       memcpy(pChange->aSub, pChange->pSub1, sz);
878       switch( pChange->aSub[0] ){
879         case 0x01:
880         case 0x02:
881           iMod = fuzzRandomInt(8) + 1;
882           break;
883 
884         case 0x03:                    /* text */
885         case 0x04: {                  /* blob */
886           int nByte;
887           int iFirst = 1 + fuzzGetVarint(&pChange->aSub[1], &nByte);
888           if( nByte>0 ){
889             iMod = fuzzRandomInt(nByte) + iFirst;
890           }
891           break;
892         }
893       }
894 
895       if( iMod>=0 ){
896         u8 mask = (1 << fuzzRandomInt(8 - (pChange->aSub[0]==0x03)));
897         pChange->aSub[iMod] ^= mask;
898       }
899     }
900   }
901 
902   return SQLITE_OK;
903 }
904 
905 /*
906 ** Copy a single change from the input to the output changeset, making
907 ** any modifications specified by (*pFuzz).
908 */
909 static int fuzzCopyChange(
910   FuzzChangeset *pParse,
911   int iGrp,
912   FuzzChange *pFuzz,
913   u8 **pp, u8 **ppOut             /* IN/OUT: Input and output pointers */
914 ){
915   int bPS = pParse->bPatchset;
916   FuzzChangesetGroup *pGrp = pParse->apGroup[iGrp];
917   u8 *p = *pp;
918   u8 *pOut = *ppOut;
919   u8 eType = p++[0];
920   int iRec;
921   int nRec = ((eType==SQLITE_UPDATE && !bPS) ? 2 : 1);
922   int iUndef = -1;
923   int nUpdate = 0;
924 
925   u8 eNew = eType;
926   if( pFuzz->iCurrent==pFuzz->iChange && pFuzz->eType==FUZZ_CHANGE_TYPE ){
927     switch( eType ){
928       case SQLITE_INSERT:
929         eNew = SQLITE_DELETE;
930         break;
931       case SQLITE_DELETE:
932         eNew = SQLITE_UPDATE;
933         break;
934       case SQLITE_UPDATE:
935         eNew = SQLITE_INSERT;
936         break;
937     }
938   }
939 
940   if( pFuzz->iCurrent==pFuzz->iChange
941    && pFuzz->eType==FUZZ_CHANGE_FIELD && eType==SQLITE_UPDATE
942   ){
943     int sz;
944     int i;
945     int nDef = 0;
946     u8 *pCsr = p+1;
947     for(i=0; i<pGrp->nCol; i++){
948       if( pCsr[0] && pGrp->aPK[i]==0 ) nDef++;
949       fuzzChangeSize(pCsr, &sz);
950       pCsr += sz;
951     }
952     if( nDef<=1 ) return -1;
953     nDef = fuzzRandomInt(nDef);
954     pCsr = p+1;
955     for(i=0; i<pGrp->nCol; i++){
956       if( pCsr[0] && pGrp->aPK[i]==0 ){
957         if( nDef==0 ) iUndef = i;
958         nDef--;
959       }
960       fuzzChangeSize(pCsr, &sz);
961       pCsr += sz;
962     }
963   }
964 
965   /* Copy the change type and indirect flag. If the fuzz mode is
966   ** FUZZ_CHANGE_INDIRECT, and the current change is the one selected for
967   ** fuzzing, invert the indirect flag.  */
968   *(pOut++) = eNew;
969   if( pFuzz->eType==FUZZ_CHANGE_INDIRECT && pFuzz->iCurrent==pFuzz->iChange ){
970     *(pOut++) = !(*(p++));
971   }else{
972     *(pOut++) = *(p++);
973   }
974 
975   for(iRec=0; iRec<nRec; iRec++){
976     int i;
977 
978     /* Copy the next record from the output to the input.
979     */
980     for(i=0; i<pGrp->nCol; i++){
981       int sz;
982       u8 *pCopy = p;
983 
984       /* If this is a patchset, and the input is a DELETE, then the only
985       ** fields present are the PK fields. So, if this is not a PK, skip to
986       ** the next column. If the current fuzz is FUZZ_CHANGE_TYPE, then
987       ** write a randomly selected value to the output.  */
988       if( bPS && eType==SQLITE_DELETE && pGrp->aPK[i]==0 ){
989         if( eType!=eNew ){
990           assert( eNew==SQLITE_UPDATE );
991           do {
992             pCopy = pParse->apVal[fuzzRandomInt(pParse->nVal)];
993           }while( pCopy[0]==0x00 );
994           fuzzChangeSize(pCopy, &sz);
995           memcpy(pOut, pCopy, sz);
996           pOut += sz;
997         }
998         continue;
999       }
1000 
1001       if( p==pFuzz->pSub1 ){
1002         pCopy = pFuzz->pSub2;
1003       }else if( p==pFuzz->pSub2 ){
1004         pCopy = pFuzz->pSub1;
1005       }else if( i==iUndef ){
1006         pCopy = "\0";
1007       }
1008 
1009       if( pCopy[0]==0x00 && eNew!=eType && eType==SQLITE_UPDATE && iRec==0 ){
1010         while( pCopy[0]==0x00 ){
1011           pCopy = pParse->apVal[fuzzRandomInt(pParse->nVal)];
1012         }
1013       }else if( p[0]==0x00 && pCopy[0]!=0x00 ){
1014         return -1;
1015       }else{
1016         if( pGrp->aPK[i]>0 && pCopy[0]==0x05 ) return -1;
1017       }
1018 
1019       if( (pFuzz->iGroup!=iGrp || i!=pFuzz->iDelete)
1020        && (eNew==eType || eType!=SQLITE_UPDATE || iRec==0)
1021        && (eNew==eType || eNew!=SQLITE_DELETE || !bPS || pGrp->aPK[i])
1022       ){
1023         fuzzChangeSize(pCopy, &sz);
1024         memcpy(pOut, pCopy, sz);
1025         pOut += sz;
1026         nUpdate += (pGrp->aPK[i]==0 && pCopy[0]!=0x00);
1027       }
1028 
1029       fuzzChangeSize(p, &sz);
1030       p += sz;
1031     }
1032 
1033     if( iGrp==pFuzz->iGroup ){
1034       if( pFuzz->eType==FUZZ_COLUMN_ADD ){
1035         if( !bPS || eType!=SQLITE_DELETE ) *(pOut++) = 0x05;
1036       }else if( pFuzz->eType==FUZZ_COLUMN_ADDPK ){
1037         if( iRec==1 ){
1038           *(pOut++) = 0x00;
1039         }else{
1040           u8 *pNew;
1041           int szNew;
1042           do {
1043             pNew = pParse->apVal[fuzzRandomInt(pParse->nVal)];
1044           }while( pNew[0]==0x00 || pNew[0]==0x05 );
1045           fuzzChangeSize(pNew, &szNew);
1046           memcpy(pOut, pNew, szNew);
1047           pOut += szNew;
1048         }
1049       }
1050     }
1051   }
1052 
1053   if( pFuzz->iCurrent==pFuzz->iChange ){
1054     if( pFuzz->eType==FUZZ_CHANGE_DUP ){
1055       int nByte = pOut - (*ppOut);
1056       memcpy(pOut, *ppOut, nByte);
1057       pOut += nByte;
1058     }
1059 
1060     if( pFuzz->eType==FUZZ_CHANGE_DEL ){
1061       pOut = *ppOut;
1062     }
1063     if( eNew!=eType && eNew==SQLITE_UPDATE && !bPS ){
1064       int i;
1065       u8 *pCsr = (*ppOut) + 2;
1066       for(i=0; i<pGrp->nCol; i++){
1067         int sz;
1068         u8 *pCopy = pCsr;
1069         if( pGrp->aPK[i] ) pCopy = "\0";
1070         fuzzChangeSize(pCopy, &sz);
1071         memcpy(pOut, pCopy, sz);
1072         pOut += sz;
1073         fuzzChangeSize(pCsr, &sz);
1074         pCsr += sz;
1075       }
1076     }
1077   }
1078 
1079   /* If a column is being deleted from this group, and this change was an
1080   ** UPDATE, and there are now no non-PK, non-undefined columns in the
1081   ** change, remove it altogether. */
1082   if( pFuzz->eType==FUZZ_COLUMN_DEL && pFuzz->iGroup==iGrp
1083    && eType==SQLITE_UPDATE && nUpdate==0
1084   ){
1085     pOut = *ppOut;
1086   }
1087 
1088   *pp = p;
1089   *ppOut = pOut;
1090   pFuzz->iCurrent += (eType==SQLITE_UPDATE || pFuzz->eType!=FUZZ_CHANGE_FIELD);
1091   return SQLITE_OK;
1092 }
1093 
1094 /*
1095 ** Fuzz the changeset parsed into object pParse and write the results
1096 ** to file zOut on disk. Argument pBuf points to a buffer that is guaranteed
1097 ** to be large enough to hold the fuzzed changeset.
1098 **
1099 ** Return SQLITE_OK if successful, or an SQLite error code if an error occurs.
1100 */
1101 static int fuzzDoOneFuzz(
1102   const char *zOut,               /* Filename to write modified changeset to */
1103   u8 *pBuf,                       /* Buffer to use for modified changeset */
1104   FuzzChangeset *pParse           /* Parse of input changeset */
1105 ){
1106   FuzzChange change;
1107   int iGrp;
1108   int rc = -1;
1109 
1110   while( rc<0 ){
1111     u8 *pOut = pBuf;
1112     rc = fuzzSelectChange(pParse, &change);
1113     for(iGrp=0; rc==SQLITE_OK && iGrp<pParse->nGroup; iGrp++){
1114       FuzzChangesetGroup *pGrp = pParse->apGroup[iGrp];
1115       int nTab = strlen(pGrp->zTab) + 1;
1116       int j;
1117       int nRep = 1;
1118 
1119       /* If this is the group to delete for a FUZZ_GROUP_DEL change, jump to
1120       ** the next group. Unless this is the only group in the changeset - in
1121       ** that case this change cannot be applied.
1122       **
1123       ** Or, if this is a FUZZ_GROUP_DUP, set nRep to 2 to output two
1124       ** copies of the group. */
1125       if( change.iGroup==iGrp ){
1126         if( change.eType==FUZZ_GROUP_DEL ){
1127           if( pParse->nGroup==1 ) rc = -1;
1128           continue;
1129         }
1130         else if( change.eType==FUZZ_GROUP_DUP ){
1131           nRep = 2;
1132         }
1133       }
1134 
1135       for(j=0; j<nRep; j++){
1136         int i;
1137         u8 *pSaved;
1138         u8 *p = pGrp->aChange;
1139         int nCol = pGrp->nCol;
1140         int iPKDel = 0;
1141         if( iGrp==change.iGroup ){
1142           if( change.eType==FUZZ_COLUMN_ADD
1143            || change.eType==FUZZ_COLUMN_ADDPK
1144           ){
1145             nCol++;
1146           }else if( change.eType==FUZZ_COLUMN_DEL ){
1147             nCol--;
1148             iPKDel = pGrp->aPK[change.iDelete];
1149           }
1150         }
1151 
1152         /* Output a table header */
1153         pOut++[0] = pParse->bPatchset ? 'P' : 'T';
1154         pOut += fuzzPutVarint(pOut, nCol);
1155 
1156         for(i=0; i<pGrp->nCol; i++){
1157           if( iGrp!=change.iGroup || i!=change.iDelete ){
1158             u8 v = pGrp->aPK[i];
1159             if( iPKDel && v>iPKDel ) v--;
1160             *(pOut++) = v;
1161           }
1162         }
1163         if( nCol>pGrp->nCol ){
1164           if( change.eType==FUZZ_COLUMN_ADD ){
1165             *(pOut++) = 0x00;
1166           }else{
1167             u8 max = 0;
1168             for(i=0; i<pGrp->nCol; i++){
1169               if( pGrp->aPK[i]>max ) max = pGrp->aPK[i];
1170             }
1171             *(pOut++) = max+1;
1172           }
1173         }
1174         memcpy(pOut, pGrp->zTab, nTab);
1175         pOut += nTab;
1176 
1177         /* Output the change array. */
1178         pSaved = pOut;
1179         for(i=0; rc==SQLITE_OK && i<pGrp->nChange; i++){
1180           rc = fuzzCopyChange(pParse, iGrp, &change, &p, &pOut);
1181         }
1182         if( pOut==pSaved ) rc = -1;
1183       }
1184     }
1185     if( rc==SQLITE_OK ){
1186       fuzzWriteFile(zOut, pBuf, pOut-pBuf);
1187     }
1188   }
1189 
1190   return rc;
1191 }
1192 
1193 int main(int argc, char **argv){
1194   int nRepeat = 0;                /* Number of output files */
1195   int iSeed = 0;                  /* Value of PRNG seed */
1196   const char *zInput;             /* Name of input file */
1197   void *pChangeset = 0;           /* Input changeset */
1198   int nChangeset = 0;             /* Size of input changeset in bytes */
1199   int i;                          /* Current output file */
1200   FuzzChangeset changeset;        /* Partially parsed changeset */
1201   int rc;
1202   u8 *pBuf = 0;
1203 
1204   if( argc!=4 && argc!=2 ) usage(argv[0]);
1205   zInput = argv[1];
1206 
1207   fuzzReadFile(zInput, &nChangeset, &pChangeset);
1208   rc = fuzzParseChangeset(pChangeset, nChangeset, &changeset);
1209 
1210   if( rc==SQLITE_OK ){
1211     if( argc==2 ){
1212       for(i=0; i<changeset.nGroup; i++){
1213         fuzzPrintGroup(&changeset, changeset.apGroup[i]);
1214       }
1215     }else{
1216       pBuf = (u8*)fuzzMalloc(nChangeset*2 + 1024);
1217       if( pBuf==0 ){
1218         rc = SQLITE_NOMEM;
1219       }else{
1220         iSeed = atoi(argv[2]);
1221         nRepeat = atoi(argv[3]);
1222         fuzzRandomSeed((unsigned int)iSeed);
1223         for(i=0; rc==SQLITE_OK && i<nRepeat; i++){
1224           char *zOut = sqlite3_mprintf("%s-%d", zInput, i);
1225           rc = fuzzDoOneFuzz(zOut, pBuf, &changeset);
1226           sqlite3_free(zOut);
1227         }
1228         fuzzFree(pBuf);
1229       }
1230     }
1231   }
1232 
1233   if( rc!=SQLITE_OK ){
1234     fprintf(stderr, "error while processing changeset: %d\n", rc);
1235   }
1236 
1237   return rc;
1238 }
1239 
1240