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