#include "sqlite3.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#define FUZZ_VALUE_SUB 1
#define FUZZ_VALUE_MOD 2
#define FUZZ_VALUE_RND 3
#define FUZZ_CHANGE_DUP 4
#define FUZZ_CHANGE_DEL 5
#define FUZZ_CHANGE_TYPE 6
#define FUZZ_CHANGE_FIELD 7
#define FUZZ_CHANGE_INDIRECT 8
#define FUZZ_GROUP_DUP 9
#define FUZZ_GROUP_DEL 10
#define FUZZ_GROUP_SWAP 11
#define FUZZ_COLUMN_ADD 12
#define FUZZ_COLUMN_ADDPK 13
#define FUZZ_COLUMN_DEL 14
typedef unsigned char u8;
typedef sqlite3_uint64 u64;
typedef sqlite3_int64 i64;
typedef unsigned int u32;
static void usage(const char *argv0){
fprintf(stderr, "Usage: %s FILENAME ?SEED N?\n", argv0);
exit(1);
}
static void fuzzReadFile(const char *zFilename, int *pSz, void **ppBuf){
FILE *f;
sqlite3_int64 sz;
void *pBuf;
f = fopen(zFilename, "rb");
if( f==0 ){
fprintf(stderr, "cannot open \"%s\" for reading\n", zFilename);
exit(1);
}
fseek(f, 0, SEEK_END);
sz = ftell(f);
rewind(f);
pBuf = sqlite3_malloc64( sz ? sz : 1 );
if( pBuf==0 ){
fprintf(stderr, "cannot allocate %d to hold content of \"%s\"\n",
(int)sz, zFilename);
exit(1);
}
if( sz>0 ){
if( fread(pBuf, (size_t)sz, 1, f)!=1 ){
fprintf(stderr, "cannot read all %d bytes of \"%s\"\n",
(int)sz, zFilename);
exit(1);
}
fclose(f);
}
*pSz = (int)sz;
*ppBuf = pBuf;
}
static void fuzzWriteFile(const char *zFilename, void *pBuf, int nBuf){
FILE *f;
f = fopen(zFilename, "wb");
if( f==0 ){
fprintf(stderr, "cannot open \"%s\" for writing\n", zFilename);
exit(1);
}
if( fwrite(pBuf, nBuf, 1, f)!=1 ){
fprintf(stderr, "cannot write to \"%s\"\n", zFilename);
exit(1);
}
fclose(f);
}
static int fuzzCorrupt(){
return SQLITE_CORRUPT;
}
static struct sqlite3PrngType {
unsigned char i, j;
unsigned char s[256];
} sqlite3Prng = {
0xAF, 0x28,
{
0x71, 0xF5, 0xB4, 0x6E, 0x80, 0xAB, 0x1D, 0xB8,
0xFB, 0xB7, 0x49, 0xBF, 0xFF, 0x72, 0x2D, 0x14,
0x79, 0x09, 0xE3, 0x78, 0x76, 0xB0, 0x2C, 0x0A,
0x8E, 0x23, 0xEE, 0xDF, 0xE0, 0x9A, 0x2F, 0x67,
0xE1, 0xBE, 0x0E, 0xA7, 0x08, 0x97, 0xEB, 0x77,
0x78, 0xBA, 0x9D, 0xCA, 0x49, 0x4C, 0x60, 0x9A,
0xF6, 0xBD, 0xDA, 0x7F, 0xBC, 0x48, 0x58, 0x52,
0xE5, 0xCD, 0x83, 0x72, 0x23, 0x52, 0xFF, 0x6D,
0xEF, 0x0F, 0x82, 0x29, 0xA0, 0x83, 0x3F, 0x7D,
0xA4, 0x88, 0x31, 0xE7, 0x88, 0x92, 0x3B, 0x9B,
0x3B, 0x2C, 0xC2, 0x4C, 0x71, 0xA2, 0xB0, 0xEA,
0x36, 0xD0, 0x00, 0xF1, 0xD3, 0x39, 0x17, 0x5D,
0x2A, 0x7A, 0xE4, 0xAD, 0xE1, 0x64, 0xCE, 0x0F,
0x9C, 0xD9, 0xF5, 0xED, 0xB0, 0x22, 0x5E, 0x62,
0x97, 0x02, 0xA3, 0x8C, 0x67, 0x80, 0xFC, 0x88,
0x14, 0x0B, 0x15, 0x10, 0x0F, 0xC7, 0x40, 0xD4,
0xF1, 0xF9, 0x0E, 0x1A, 0xCE, 0xB9, 0x1E, 0xA1,
0x72, 0x8E, 0xD7, 0x78, 0x39, 0xCD, 0xF4, 0x5D,
0x2A, 0x59, 0x26, 0x34, 0xF2, 0x73, 0x0B, 0xA0,
0x02, 0x51, 0x2C, 0x03, 0xA3, 0xA7, 0x43, 0x13,
0xE8, 0x98, 0x2B, 0xD2, 0x53, 0xF8, 0xEE, 0x91,
0x7D, 0xE7, 0xE3, 0xDA, 0xD5, 0xBB, 0xC0, 0x92,
0x9D, 0x98, 0x01, 0x2C, 0xF9, 0xB9, 0xA0, 0xEB,
0xCF, 0x32, 0xFA, 0x01, 0x49, 0xA5, 0x1D, 0x9A,
0x76, 0x86, 0x3F, 0x40, 0xD4, 0x89, 0x8F, 0x9C,
0xE2, 0xE3, 0x11, 0x31, 0x37, 0xB2, 0x49, 0x28,
0x35, 0xC0, 0x99, 0xB6, 0xD0, 0xBC, 0x66, 0x35,
0xF7, 0x83, 0x5B, 0xD7, 0x37, 0x1A, 0x2B, 0x18,
0xA6, 0xFF, 0x8D, 0x7C, 0x81, 0xA8, 0xFC, 0x9E,
0xC4, 0xEC, 0x80, 0xD0, 0x98, 0xA7, 0x76, 0xCC,
0x9C, 0x2F, 0x7B, 0xFF, 0x8E, 0x0E, 0xBB, 0x90,
0xAE, 0x13, 0x06, 0xF5, 0x1C, 0x4E, 0x52, 0xF7
}
};
static unsigned char fuzzRandomByte(void){
unsigned char t;
sqlite3Prng.i++;
t = sqlite3Prng.s[sqlite3Prng.i];
sqlite3Prng.j += t;
sqlite3Prng.s[sqlite3Prng.i] = sqlite3Prng.s[sqlite3Prng.j];
sqlite3Prng.s[sqlite3Prng.j] = t;
t += sqlite3Prng.s[sqlite3Prng.i];
return sqlite3Prng.s[t];
}
static void fuzzRandomBlob(int nBuf, unsigned char *zBuf){
int i;
for(i=0; i<nBuf; i++){
zBuf[i] = fuzzRandomByte();
}
}
static unsigned int fuzzRandomInt(unsigned int nRange){
unsigned int ret;
assert( nRange>0 );
fuzzRandomBlob(sizeof(ret), (unsigned char*)&ret);
return (ret % nRange);
}
static u64 fuzzRandomU64(){
u64 ret;
fuzzRandomBlob(sizeof(ret), (unsigned char*)&ret);
return ret;
}
static void fuzzRandomSeed(unsigned int iSeed){
int i;
for(i=0; i<256; i+=4){
sqlite3Prng.s[i] ^= ((iSeed >> 24) & 0xFF);
sqlite3Prng.s[i+1] ^= ((iSeed >> 16) & 0xFF);
sqlite3Prng.s[i+2] ^= ((iSeed >> 8) & 0xFF);
sqlite3Prng.s[i+3] ^= ((iSeed >> 0) & 0xFF);
}
}
typedef struct FuzzChangeset FuzzChangeset;
typedef struct FuzzChangesetGroup FuzzChangesetGroup;
typedef struct FuzzChange FuzzChange;
struct FuzzChangeset {
int bPatchset;
FuzzChangesetGroup **apGroup;
int nGroup;
u8 **apVal;
int nVal;
int nChange;
int nUpdate;
};
struct FuzzChangesetGroup {
const char *zTab;
int nCol;
u8 *aPK;
u8 *aChange;
int szChange;
int nChange;
};
struct FuzzChange {
int eType;
int iChange;
int iGroup;
int iDelete;
u8 *pSub1;
u8 *pSub2;
u8 aSub[128];
int iCurrent;
};
static void *fuzzMalloc(sqlite3_int64 nByte){
void *pRet = sqlite3_malloc64(nByte);
if( pRet ){
memset(pRet, 0, (size_t)nByte);
}
return pRet;
}
static void fuzzFree(void *p){
sqlite3_free(p);
}
static int fuzzGetVarint(u8 *p, int *pnVal){
int i;
sqlite3_uint64 nVal = 0;
for(i=0; i<9; i++){
nVal = (nVal<<7) + (p[i] & 0x7F);
if( (p[i] & 0x80)==0 ){
i++;
break;
}
}
*pnVal = (int)nVal;
return i;
}
static int fuzzPutVarint(u8 *p, int nVal){
assert( nVal>0 && nVal<2097152 );
if( nVal<128 ){
p[0] = (u8)nVal;
return 1;
}
if( nVal<16384 ){
p[0] = ((nVal >> 7) & 0x7F) | 0x80;
p[1] = (nVal & 0x7F);
return 2;
}
p[0] = ((nVal >> 14) & 0x7F) | 0x80;
p[1] = ((nVal >> 7) & 0x7F) | 0x80;
p[2] = (nVal & 0x7F);
return 3;
}
static i64 fuzzGetI64(u8 *aRec){
return (i64)(
(((u64)aRec[0]) << 56)
+ (((u64)aRec[1]) << 48)
+ (((u64)aRec[2]) << 40)
+ (((u64)aRec[3]) << 32)
+ (((u64)aRec[4]) << 24)
+ (((u64)aRec[5]) << 16)
+ (((u64)aRec[6]) << 8)
+ (((u64)aRec[7]) << 0)
);
}
static void fuzzPutU64(u8 *aRec, u64 iVal){
aRec[0] = (iVal>>56) & 0xFF;
aRec[1] = (iVal>>48) & 0xFF;
aRec[2] = (iVal>>40) & 0xFF;
aRec[3] = (iVal>>32) & 0xFF;
aRec[4] = (iVal>>24) & 0xFF;
aRec[5] = (iVal>>16) & 0xFF;
aRec[6] = (iVal>> 8) & 0xFF;
aRec[7] = (iVal) & 0xFF;
}
static int fuzzParseHeader(
FuzzChangeset *pParse,
u8 **ppHdr,
u8 *pEnd,
FuzzChangesetGroup **ppGrp
){
int rc = SQLITE_OK;
FuzzChangesetGroup *pGrp;
u8 cHdr = (pParse->bPatchset ? 'P' : 'T');
assert( pEnd>(*ppHdr) );
pGrp = (FuzzChangesetGroup*)fuzzMalloc(sizeof(FuzzChangesetGroup));
if( !pGrp ){
rc = SQLITE_NOMEM;
}else{
u8 *p = *ppHdr;
if( p[0]!=cHdr ){
rc = fuzzCorrupt();
}else{
p++;
p += fuzzGetVarint(p, &pGrp->nCol);
pGrp->aPK = p;
p += pGrp->nCol;
pGrp->zTab = (const char*)p;
p = &p[strlen((const char*)p)+1];
if( p>=pEnd ){
rc = fuzzCorrupt();
}
}
*ppHdr = p;
}
if( rc!=SQLITE_OK ){
fuzzFree(pGrp);
pGrp = 0;
}
*ppGrp = pGrp;
return rc;
}
static int fuzzChangeSize(u8 *p, int *pSz){
u8 eType = p[0];
switch( eType ){
case 0x00:
case 0x05:
*pSz = 1;
break;
case 0x01:
case 0x02:
*pSz = 9;
break;
case 0x03:
case 0x04: {
int nTxt;
int sz;
sz = fuzzGetVarint(&p[1], &nTxt);
*pSz = 1 + sz + nTxt;
break;
}
default:
return fuzzCorrupt();
}
return SQLITE_OK;
}
static int fuzzParseRecord(
u8 **ppRec,
u8 *pEnd,
FuzzChangeset *pParse,
int bPkOnly
){
int rc = SQLITE_OK;
FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1];
int i;
u8 *p = *ppRec;
for(i=0; rc==SQLITE_OK && i<pGrp->nCol; i++){
if( bPkOnly==0 || pGrp->aPK[i] ){
int sz;
if( p>=pEnd ) break;
if( (pParse->nVal & (pParse->nVal-1))==0 ){
int nNew = pParse->nVal ? pParse->nVal*2 : 4;
u8 **apNew = (u8**)sqlite3_realloc(pParse->apVal, nNew*sizeof(u8*));
if( apNew==0 ) return SQLITE_NOMEM;
pParse->apVal = apNew;
}
pParse->apVal[pParse->nVal++] = p;
rc = fuzzChangeSize(p, &sz);
p += sz;
}
}
if( rc==SQLITE_OK && i<pGrp->nCol ){
rc = fuzzCorrupt();
}
*ppRec = p;
return rc;
}
static int fuzzParseChanges(u8 **ppData, u8 *pEnd, FuzzChangeset *pParse){
u8 cHdr = (pParse->bPatchset ? 'P' : 'T');
FuzzChangesetGroup *pGrp = pParse->apGroup[pParse->nGroup-1];
int rc = SQLITE_OK;
u8 *p = *ppData;
pGrp->aChange = p;
while( rc==SQLITE_OK && p<pEnd && p[0]!=cHdr ){
u8 eOp = p[0];
u8 bIndirect = p[1];
p += 2;
if( eOp==SQLITE_UPDATE ){
pParse->nUpdate++;
if( pParse->bPatchset==0 ){
rc = fuzzParseRecord(&p, pEnd, pParse, 0);
}
}else if( eOp!=SQLITE_INSERT && eOp!=SQLITE_DELETE ){
rc = fuzzCorrupt();
}
if( rc==SQLITE_OK ){
int bPkOnly = (eOp==SQLITE_DELETE && pParse->bPatchset);
rc = fuzzParseRecord(&p, pEnd, pParse, bPkOnly);
}
pGrp->nChange++;
pParse->nChange++;
}
pGrp->szChange = p - pGrp->aChange;
*ppData = p;
return rc;
}
static int fuzzParseChangeset(
u8 *pChangeset,
int nChangeset,
FuzzChangeset *pParse
){
u8 *pEnd = &pChangeset[nChangeset];
u8 *p = pChangeset;
int rc = SQLITE_OK;
memset(pParse, 0, sizeof(FuzzChangeset));
if( nChangeset>0 ){
pParse->bPatchset = (pChangeset[0]=='P');
}
while( rc==SQLITE_OK && p<pEnd ){
FuzzChangesetGroup *pGrp = 0;
rc = fuzzParseHeader(pParse, &p, pEnd, &pGrp);
assert( (rc==SQLITE_OK)==(pGrp!=0) );
if( rc==SQLITE_OK ){
FuzzChangesetGroup **apNew = (FuzzChangesetGroup**)sqlite3_realloc64(
pParse->apGroup, sizeof(FuzzChangesetGroup*)*(pParse->nGroup+1)
);
if( apNew==0 ){
rc = SQLITE_NOMEM;
}else{
apNew[pParse->nGroup] = pGrp;
pParse->apGroup = apNew;
pParse->nGroup++;
}
rc = fuzzParseChanges(&p, pEnd, pParse);
}
}
return rc;
}
static int fuzzPrintRecord(FuzzChangesetGroup *pGrp, u8 **ppRec, int bPKOnly){
int rc = SQLITE_OK;
u8 *p = *ppRec;
int i;
const char *zPre = " (";
for(i=0; i<pGrp->nCol; i++){
if( bPKOnly==0 || pGrp->aPK[i] ){
u8 eType = p++[0];
switch( eType ){
case 0x00:
printf("%sn/a", zPre);
break;
case 0x01: {
sqlite3_int64 iVal = 0;
iVal = fuzzGetI64(p);
printf("%s%lld", zPre, iVal);
p += 8;
break;
}
case 0x02: {
sqlite3_int64 iVal = 0;
double fVal = 0.0;
iVal = fuzzGetI64(p);
memcpy(&fVal, &iVal, 8);
printf("%s%f", zPre, fVal);
p += 8;
break;
}
case 0x03:
case 0x04: {
int nTxt;
p += fuzzGetVarint(p, &nTxt);
printf("%s%s", zPre, eType==0x03 ? "'" : "X'");
for(i=0; i<nTxt; i++){
if( eType==0x03 ){
printf("%c", p[i]);
}else{
char aHex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
printf("%c", aHex[ p[i]>>4 ]);
printf("%c", aHex[ p[i] & 0x0F ]);
}
}
printf("'");
p += nTxt;
break;
}
case 0x05:
printf("%sNULL", zPre);
break;
}
zPre = ", ";
}
}
printf(")");
*ppRec = p;
return rc;
}
static void fuzzPrintGroup(FuzzChangeset *pParse, FuzzChangesetGroup *pGrp){
int i;
u8 *p;
printf("TABLE: %s nCol=%d aPK=", pGrp->zTab, pGrp->nCol);
for(i=0; i<pGrp->nCol; i++){
printf("%d", (int)pGrp->aPK[i]);
}
printf("\n");
p = pGrp->aChange;
for(i=0; i<pGrp->nChange; i++){
u8 eType = p[0];
u8 bIndirect = p[1];
printf("%s (ind=%d):",
(eType==SQLITE_INSERT) ? "INSERT" :
(eType==SQLITE_DELETE ? "DELETE" : "UPDATE"),
bIndirect
);
p += 2;
if( pParse->bPatchset==0 && eType==SQLITE_UPDATE ){
fuzzPrintRecord(pGrp, &p, 0);
}
fuzzPrintRecord(pGrp, &p, eType==SQLITE_DELETE && pParse->bPatchset);
printf("\n");
}
}
static int fuzzSelectChange(FuzzChangeset *pParse, FuzzChange *pChange){
int iSub;
memset(pChange, 0, sizeof(FuzzChange));
pChange->eType = fuzzRandomInt(FUZZ_COLUMN_DEL) + 1;
assert( pChange->eType==FUZZ_VALUE_SUB
|| pChange->eType==FUZZ_VALUE_MOD
|| pChange->eType==FUZZ_VALUE_RND
|| pChange->eType==FUZZ_CHANGE_DUP
|| pChange->eType==FUZZ_CHANGE_DEL
|| pChange->eType==FUZZ_CHANGE_TYPE
|| pChange->eType==FUZZ_CHANGE_FIELD
|| pChange->eType==FUZZ_CHANGE_INDIRECT
|| pChange->eType==FUZZ_GROUP_DUP
|| pChange->eType==FUZZ_GROUP_DEL
|| pChange->eType==FUZZ_GROUP_SWAP
|| pChange->eType==FUZZ_COLUMN_ADD
|| pChange->eType==FUZZ_COLUMN_ADDPK
|| pChange->eType==FUZZ_COLUMN_DEL
);
pChange->iGroup = fuzzRandomInt(pParse->nGroup);
pChange->iChange = fuzzRandomInt(pParse->nChange);
if( pChange->eType==FUZZ_CHANGE_FIELD ){
if( pParse->nUpdate==0 ) return -1;
pChange->iChange = fuzzRandomInt(pParse->nUpdate);
}
pChange->iDelete = -1;
if( pChange->eType==FUZZ_COLUMN_DEL ){
FuzzChangesetGroup *pGrp = pParse->apGroup[pChange->iGroup];
int i;
pChange->iDelete = fuzzRandomInt(pGrp->nCol);
for(i=pGrp->nCol-1; i>=0; i--){
if( pGrp->aPK[i] && pChange->iDelete!=i ) break;
}
if( i<0 ) return -1;
}
if( pChange->eType==FUZZ_GROUP_SWAP ){
FuzzChangesetGroup *pGrp;
int iGrp = pChange->iGroup;
if( pParse->nGroup==1 ) return -1;
while( iGrp==pChange->iGroup ){
iGrp = fuzzRandomInt(pParse->nGroup);
}
pGrp = pParse->apGroup[pChange->iGroup];
pParse->apGroup[pChange->iGroup] = pParse->apGroup[iGrp];
pParse->apGroup[iGrp] = pGrp;
}
if( pChange->eType==FUZZ_VALUE_SUB
|| pChange->eType==FUZZ_VALUE_MOD
|| pChange->eType==FUZZ_VALUE_RND
){
iSub = fuzzRandomInt(pParse->nVal);
pChange->pSub1 = pParse->apVal[iSub];
if( pChange->eType==FUZZ_VALUE_SUB ){
iSub = fuzzRandomInt(pParse->nVal);
pChange->pSub2 = pParse->apVal[iSub];
}else{
pChange->pSub2 = pChange->aSub;
}
if( pChange->eType==FUZZ_VALUE_RND ){
pChange->aSub[0] = (u8)(fuzzRandomInt(5) + 1);
switch( pChange->aSub[0] ){
case 0x01: {
u64 iVal = fuzzRandomU64();
fuzzPutU64(&pChange->aSub[1], iVal);
break;
}
case 0x02: {
u64 iVal1 = fuzzRandomU64();
u64 iVal2 = fuzzRandomU64();
double d = (double)iVal1 / (double)iVal2;
memcpy(&iVal1, &d, sizeof(iVal1));
fuzzPutU64(&pChange->aSub[1], iVal1);
break;
}
case 0x03:
case 0x04: {
int nByte = fuzzRandomInt(48);
pChange->aSub[1] = (u8)nByte;
fuzzRandomBlob(nByte, &pChange->aSub[2]);
if( pChange->aSub[0]==0x03 ){
int i;
for(i=0; i<nByte; i++){
pChange->aSub[2+i] &= 0x7F;
}
}
break;
}
}
}
if( pChange->eType==FUZZ_VALUE_MOD ){
int sz;
int iMod = -1;
fuzzChangeSize(pChange->pSub1, &sz);
memcpy(pChange->aSub, pChange->pSub1, sz);
switch( pChange->aSub[0] ){
case 0x01:
case 0x02:
iMod = fuzzRandomInt(8) + 1;
break;
case 0x03:
case 0x04: {
int nByte;
int iFirst = 1 + fuzzGetVarint(&pChange->aSub[1], &nByte);
if( nByte>0 ){
iMod = fuzzRandomInt(nByte) + iFirst;
}
break;
}
}
if( iMod>=0 ){
u8 mask = (1 << fuzzRandomInt(8 - (pChange->aSub[0]==0x03)));
pChange->aSub[iMod] ^= mask;
}
}
}
return SQLITE_OK;
}
static int fuzzCopyChange(
FuzzChangeset *pParse,
int iGrp,
FuzzChange *pFuzz,
u8 **pp, u8 **ppOut
){
int bPS = pParse->bPatchset;
FuzzChangesetGroup *pGrp = pParse->apGroup[iGrp];
u8 *p = *pp;
u8 *pOut = *ppOut;
u8 eType = p++[0];
int iRec;
int nRec = ((eType==SQLITE_UPDATE && !bPS) ? 2 : 1);
int iUndef = -1;
int nUpdate = 0;
u8 eNew = eType;
if( pFuzz->iCurrent==pFuzz->iChange && pFuzz->eType==FUZZ_CHANGE_TYPE ){
switch( eType ){
case SQLITE_INSERT:
eNew = SQLITE_DELETE;
break;
case SQLITE_DELETE:
eNew = SQLITE_UPDATE;
break;
case SQLITE_UPDATE:
eNew = SQLITE_INSERT;
break;
}
}
if( pFuzz->iCurrent==pFuzz->iChange
&& pFuzz->eType==FUZZ_CHANGE_FIELD && eType==SQLITE_UPDATE
){
int sz;
int i;
int nDef = 0;
u8 *pCsr = p+1;
for(i=0; i<pGrp->nCol; i++){
if( pCsr[0] && pGrp->aPK[i]==0 ) nDef++;
fuzzChangeSize(pCsr, &sz);
pCsr += sz;
}
if( nDef<=1 ) return -1;
nDef = fuzzRandomInt(nDef);
pCsr = p+1;
for(i=0; i<pGrp->nCol; i++){
if( pCsr[0] && pGrp->aPK[i]==0 ){
if( nDef==0 ) iUndef = i;
nDef--;
}
fuzzChangeSize(pCsr, &sz);
pCsr += sz;
}
}
*(pOut++) = eNew;
if( pFuzz->eType==FUZZ_CHANGE_INDIRECT && pFuzz->iCurrent==pFuzz->iChange ){
*(pOut++) = !(*(p++));
}else{
*(pOut++) = *(p++);
}
for(iRec=0; iRec<nRec; iRec++){
int i;
for(i=0; i<pGrp->nCol; i++){
int sz;
u8 *pCopy = p;
if( bPS && eType==SQLITE_DELETE && pGrp->aPK[i]==0 ){
if( eType!=eNew ){
assert( eNew==SQLITE_UPDATE );
do {
pCopy = pParse->apVal[fuzzRandomInt(pParse->nVal)];
}while( pCopy[0]==0x00 );
fuzzChangeSize(pCopy, &sz);
memcpy(pOut, pCopy, sz);
pOut += sz;
}
continue;
}
if( p==pFuzz->pSub1 ){
pCopy = pFuzz->pSub2;
}else if( p==pFuzz->pSub2 ){
pCopy = pFuzz->pSub1;
}else if( i==iUndef ){
pCopy = (u8*)"\0";
}
if( pCopy[0]==0x00 && eNew!=eType && eType==SQLITE_UPDATE && iRec==0 ){
while( pCopy[0]==0x00 ){
pCopy = pParse->apVal[fuzzRandomInt(pParse->nVal)];
}
}else if( p[0]==0x00 && pCopy[0]!=0x00 ){
return -1;
}else{
if( pGrp->aPK[i]>0 && pCopy[0]==0x05 ) return -1;
}
if( (pFuzz->iGroup!=iGrp || i!=pFuzz->iDelete)
&& (eNew==eType || eType!=SQLITE_UPDATE || iRec==0)
&& (eNew==eType || eNew!=SQLITE_DELETE || !bPS || pGrp->aPK[i])
){
fuzzChangeSize(pCopy, &sz);
memcpy(pOut, pCopy, sz);
pOut += sz;
nUpdate += (pGrp->aPK[i]==0 && pCopy[0]!=0x00);
}
fuzzChangeSize(p, &sz);
p += sz;
}
if( iGrp==pFuzz->iGroup ){
if( pFuzz->eType==FUZZ_COLUMN_ADD ){
if( !bPS || eType!=SQLITE_DELETE ) *(pOut++) = 0x05;
}else if( pFuzz->eType==FUZZ_COLUMN_ADDPK ){
if( iRec==1 ){
*(pOut++) = 0x00;
}else{
u8 *pNew;
int szNew;
do {
pNew = pParse->apVal[fuzzRandomInt(pParse->nVal)];
}while( pNew[0]==0x00 || pNew[0]==0x05 );
fuzzChangeSize(pNew, &szNew);
memcpy(pOut, pNew, szNew);
pOut += szNew;
}
}
}
}
if( pFuzz->iCurrent==pFuzz->iChange ){
if( pFuzz->eType==FUZZ_CHANGE_DUP ){
int nByte = pOut - (*ppOut);
memcpy(pOut, *ppOut, nByte);
pOut += nByte;
}
if( pFuzz->eType==FUZZ_CHANGE_DEL ){
pOut = *ppOut;
}
if( eNew!=eType && eNew==SQLITE_UPDATE && !bPS ){
int i;
u8 *pCsr = (*ppOut) + 2;
for(i=0; i<pGrp->nCol; i++){
int sz;
u8 *pCopy = pCsr;
if( pGrp->aPK[i] ) pCopy = (u8*)"\0";
fuzzChangeSize(pCopy, &sz);
memcpy(pOut, pCopy, sz);
pOut += sz;
fuzzChangeSize(pCsr, &sz);
pCsr += sz;
}
}
}
if( pFuzz->eType==FUZZ_COLUMN_DEL && pFuzz->iGroup==iGrp
&& eType==SQLITE_UPDATE && nUpdate==0
){
pOut = *ppOut;
}
*pp = p;
*ppOut = pOut;
pFuzz->iCurrent += (eType==SQLITE_UPDATE || pFuzz->eType!=FUZZ_CHANGE_FIELD);
return SQLITE_OK;
}
static int fuzzDoOneFuzz(
const char *zOut,
u8 *pBuf,
FuzzChangeset *pParse
){
FuzzChange change;
int iGrp;
int rc = -1;
while( rc<0 ){
u8 *pOut = pBuf;
rc = fuzzSelectChange(pParse, &change);
for(iGrp=0; rc==SQLITE_OK && iGrp<pParse->nGroup; iGrp++){
FuzzChangesetGroup *pGrp = pParse->apGroup[iGrp];
int nTab = strlen(pGrp->zTab) + 1;
int j;
int nRep = 1;
if( change.iGroup==iGrp ){
if( change.eType==FUZZ_GROUP_DEL ){
if( pParse->nGroup==1 ) rc = -1;
continue;
}
else if( change.eType==FUZZ_GROUP_DUP ){
nRep = 2;
}
}
for(j=0; j<nRep; j++){
int i;
u8 *pSaved;
u8 *p = pGrp->aChange;
int nCol = pGrp->nCol;
int iPKDel = 0;
if( iGrp==change.iGroup ){
if( change.eType==FUZZ_COLUMN_ADD
|| change.eType==FUZZ_COLUMN_ADDPK
){
nCol++;
}else if( change.eType==FUZZ_COLUMN_DEL ){
nCol--;
iPKDel = pGrp->aPK[change.iDelete];
}
}
pOut++[0] = pParse->bPatchset ? 'P' : 'T';
pOut += fuzzPutVarint(pOut, nCol);
for(i=0; i<pGrp->nCol; i++){
if( iGrp!=change.iGroup || i!=change.iDelete ){
u8 v = pGrp->aPK[i];
if( iPKDel && v>iPKDel ) v--;
*(pOut++) = v;
}
}
if( nCol>pGrp->nCol ){
if( change.eType==FUZZ_COLUMN_ADD ){
*(pOut++) = 0x00;
}else{
u8 max = 0;
for(i=0; i<pGrp->nCol; i++){
if( pGrp->aPK[i]>max ) max = pGrp->aPK[i];
}
*(pOut++) = max+1;
}
}
memcpy(pOut, pGrp->zTab, nTab);
pOut += nTab;
pSaved = pOut;
for(i=0; rc==SQLITE_OK && i<pGrp->nChange; i++){
rc = fuzzCopyChange(pParse, iGrp, &change, &p, &pOut);
}
if( pOut==pSaved ) rc = -1;
}
}
if( rc==SQLITE_OK ){
fuzzWriteFile(zOut, pBuf, pOut-pBuf);
}
}
return rc;
}
int main(int argc, char **argv){
int nRepeat = 0;
int iSeed = 0;
const char *zInput;
void *pChangeset = 0;
int nChangeset = 0;
int i;
FuzzChangeset changeset;
int rc;
u8 *pBuf = 0;
if( argc!=4 && argc!=2 ) usage(argv[0]);
zInput = argv[1];
fuzzReadFile(zInput, &nChangeset, &pChangeset);
rc = fuzzParseChangeset(pChangeset, nChangeset, &changeset);
if( rc==SQLITE_OK ){
if( argc==2 ){
for(i=0; i<changeset.nGroup; i++){
fuzzPrintGroup(&changeset, changeset.apGroup[i]);
}
}else{
pBuf = (u8*)fuzzMalloc((sqlite3_int64)nChangeset*2 + 1024);
if( pBuf==0 ){
rc = SQLITE_NOMEM;
}else{
iSeed = atoi(argv[2]);
nRepeat = atoi(argv[3]);
fuzzRandomSeed((unsigned int)iSeed);
for(i=0; rc==SQLITE_OK && i<nRepeat; i++){
char *zOut = sqlite3_mprintf("%s-%d", zInput, i);
rc = fuzzDoOneFuzz(zOut, pBuf, &changeset);
sqlite3_free(zOut);
}
fuzzFree(pBuf);
}
}
}
if( rc!=SQLITE_OK ){
fprintf(stderr, "error while processing changeset: %d\n", rc);
}
return rc;
}