/ Check-in [141a93c8]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Update the changesetfuzz program to fuzz changeset schemas as well as data.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | changesetfuzz
Files: files | file ages | folders
SHA3-256: 141a93c843d501d8bb640228645ead0a83870c1c11e9d4b07ed24b296c69a0b8
User & Date: dan 2018-11-06 20:08:03
Context
2018-11-07
17:52
Update the "changesetfuzz" program to work with patchsets as well as changesets. check-in: 75b00fbe user: dan tags: changesetfuzz
2018-11-06
20:08
Update the changesetfuzz program to fuzz changeset schemas as well as data. check-in: 141a93c8 user: dan tags: changesetfuzz
2018-11-05
20:37
Add preliminary version of "changesetfuzz" program. For fuzzing changeset data without creating corrupt changesets. check-in: 81ac8745 user: dan tags: changesetfuzz
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/session/changesetfuzz.c.

    58     58   **   6. A single change may have its type (INSERT, DELETE, UPDATE) changed.
    59     59   **      If an INSERT is changed to a DELETE (or vice versa), the type is
    60     60   **      simply changed - no other modifications are required. If an INSERT
    61     61   **      or DELETE is changed to an UPDATE, then the single record is duplicated
    62     62   **      (as both the old.* and new.* records of the new UPDATE change). If an
    63     63   **      UPDATE is changed to a DELETE or INSERT, the new.* record is discarded
    64     64   **      and any "undefined" fields replaced with pseudo-randomly generated
    65         -**      values. 
           65  +**      values.
    66     66   **
    67     67   **   7. An UPDATE change that modifies N table columns may be modified so
    68     68   **      that it updates N-1 columns, so long as (N>1).
    69     69   **
           70  +**   8. The "indirect" flag may be toggled for any change.
           71  +**
           72  +** Entire group of changes may also be operated on:
           73  +**
           74  +**   9. Duplicate an existing group.
           75  +**
           76  +**  10. Remove an existing group.
           77  +**
           78  +**  11. The positions of two groups may be exchanged.
           79  +**
           80  +** There are also schema changes:
           81  +**
           82  +**  12. A non-PK column may be added to a table. In this case a NULL 
           83  +**      value is appended to all records.
           84  +**
           85  +**  13. A PK column may be added to a table. In this case a non-NULL 
           86  +**      value is appended to all INSERT, DELETE and UPDATE old.* records.
           87  +**      An "undefined" is appended to new.* UPDATE records.
           88  +**
           89  +**  14. A column may be removed from a table.  In this case the corresponding
           90  +**      field is removed from all records. In cases where this leaves an UPDATE
           91  +**      with no non-PK, non-undefined fields, the entire change is removed. If
           92  +**      the table has more than on PK column, the column removed may be part of
           93  +**      the PK. 
    70     94   */
    71     95   
    72     96   #include "sqlite3.h"
    73     97   #include <stdio.h>
    74     98   #include <stdlib.h>
    75     99   #include <string.h>
    76    100   #include <assert.h>
    77    101   #include <ctype.h>
    78    102   
    79         -#define FUZZ_VALUE_SUB     1      /* Replace one value with a copy of another */
    80         -#define FUZZ_VALUE_MOD     2      /* Modify content by 1 bit */
    81         -#define FUZZ_VALUE_RND     3      /* Replace with pseudo-random value */
          103  +#define FUZZ_VALUE_SUB       1    /* Replace one value with a copy of another */
          104  +#define FUZZ_VALUE_MOD       2    /* Modify content by 1 bit */
          105  +#define FUZZ_VALUE_RND       3    /* Replace with pseudo-random value */
    82    106   
    83         -#define FUZZ_CHANGE_DUP    4
    84         -#define FUZZ_CHANGE_DEL    5
    85         -#define FUZZ_CHANGE_TYPE   6
    86         -#define FUZZ_CHANGE_FIELD  7
          107  +#define FUZZ_CHANGE_DUP      4    /* Duplicate an existing change */
          108  +#define FUZZ_CHANGE_DEL      5    /* Completely remove one change */
          109  +#define FUZZ_CHANGE_TYPE     6    /* Change the type of one change */
          110  +#define FUZZ_CHANGE_FIELD    7    /* Change an UPDATE to modify fewer columns */
          111  +#define FUZZ_CHANGE_INDIRECT 8    /* Toggle the "indirect" flag of a change */
          112  +
          113  +#define FUZZ_GROUP_DUP       9    /* Duplicate a change group */
          114  +#define FUZZ_GROUP_DEL      10    /* Delete an entire change group */
          115  +#define FUZZ_GROUP_SWAP     11    /* Exchange the position of two groups */
          116  +
          117  +#define FUZZ_COLUMN_ADD     12     /* Add column to table definition */
          118  +#define FUZZ_COLUMN_ADDPK   13     /* Add PK column to table definition */
          119  +#define FUZZ_COLUMN_DEL     14     /* Remove column from table definition */
    87    120   
    88    121   #if 0
    89    122   #define FUZZ_COLUMN_ADD    1      /* Add column to table definition */
    90         -#define FUZZ_COLUMN_DEL    2      /* Remove column from table definition */
    91    123   #define FUZZ_PK_ADD        3      /* Add a PK column */
    92    124   #define FUZZ_PK_DEL        4      /* Delete a PK column */
    93    125   #define FUZZ_NAME_CHANGE   5      /* Change a table name */
    94    126   #endif
    95    127   
    96    128   
    97    129   
................................................................................
   270    302   
   271    303   /* 
   272    304   ** Object containing partially parsed changeset.
   273    305   */
   274    306   struct FuzzChangeset {
   275    307     FuzzChangesetGroup **apGroup;   /* Array of groups in changeset */
   276    308     int nGroup;                     /* Number of items in list pGroup */
   277         -  u8 *aVal[FUZZER_AVAL_SZ];       /* Array of first few values in changeset */
   278         -  int nVal;                       /* Number of used slots in aVal[] */
          309  +  u8 **apVal;                     /* Array of all values in changeset */
          310  +  int nVal;                       /* Number of used slots in apVal[] */
   279    311     int nChange;                    /* Number of changes in changeset */
   280    312     int nUpdate;                    /* Number of UPDATE changes in changeset */
   281    313   };
   282    314   
   283    315   struct FuzzChangesetGroup {
   284    316     const char *zTab;               /* Name of table */
   285    317     int nCol;                       /* Number of columns in table */
   286    318     u8 *aPK;                        /* PK array for this table */
   287    319     u8 *aChange;                    /* Buffer containing array of changes */
   288    320     int szChange;                   /* Size of buffer aChange[] in bytes */
   289    321     int nChange;                    /* Number of changes in buffer aChange[] */
   290         -  FuzzChangesetGroup *pNextGroup;
   291    322   };
   292    323   
   293    324   /*
   294    325   ** Description of a fuzz change to be applied to a changeset.
   295    326   */
   296    327   struct FuzzChange {
   297    328     int eType;                      /* One of the FUZZ_* constants above */
   298         -  int iChange;                    /* Change to modify */
          329  +  int iChange;                    /* Change or UPDATE to modify */
          330  +  int iGroup;                     /* Group to modify */
          331  +  int iDelete;                    /* Field to remove (FUZZ_COLUMN_DEL) */
   299    332     u8 *pSub1;
   300    333     u8 *pSub2;
   301    334     u8 aSub[128];                   /* Substitute value */
   302         -
   303    335     int iCurrent;                   /* Current change number */
   304    336   };
   305    337   
   306    338   static void *fuzzMalloc(int nByte){
   307    339     void *pRet = sqlite3_malloc(nByte);
   308    340     if( pRet ){
   309    341       memset(pRet, 0, nByte);
................................................................................
   440    472     int rc = SQLITE_OK;
   441    473     int nCol = pParse->apGroup[pParse->nGroup-1]->nCol;
   442    474     int i;
   443    475     u8 *p = *ppRec;
   444    476   
   445    477     for(i=0; rc==SQLITE_OK && i<nCol && p<pEnd; i++){
   446    478       int sz;
   447         -    if( pParse->nVal<FUZZER_AVAL_SZ ){
   448         -      pParse->aVal[pParse->nVal++] = p;
          479  +    if( (pParse->nVal & (pParse->nVal-1))==0 ){
          480  +      int nNew = pParse->nVal ? pParse->nVal*2 : 4;
          481  +      u8 **apNew = (u8**)sqlite3_realloc(pParse->apVal, nNew*sizeof(u8*));
          482  +      if( apNew==0 ) return SQLITE_NOMEM;
          483  +      pParse->apVal = apNew;
   449    484       }
          485  +    pParse->apVal[pParse->nVal++] = p;
   450    486       rc = fuzzChangeSize(p, &sz);
   451    487       p += sz;
   452    488     }
   453    489   
   454    490     if( rc==SQLITE_OK && i<nCol ){
   455    491       rc = fuzzCorrupt();
   456    492     }
................................................................................
   623    659     }
   624    660   }
   625    661   
   626    662   static int fuzzSelectChange(FuzzChangeset *pParse, FuzzChange *pChange){
   627    663     int iSub;
   628    664   
   629    665     memset(pChange, 0, sizeof(FuzzChange));
   630         -  pChange->eType = fuzzRandomInt(7) + FUZZ_VALUE_SUB;
          666  +  pChange->eType = fuzzRandomInt(14) + FUZZ_VALUE_SUB;
   631    667   
   632    668     assert( pChange->eType==FUZZ_VALUE_SUB
   633    669          || pChange->eType==FUZZ_VALUE_MOD
   634    670          || pChange->eType==FUZZ_VALUE_RND
   635    671          || pChange->eType==FUZZ_CHANGE_DUP
   636    672          || pChange->eType==FUZZ_CHANGE_DEL
   637    673          || pChange->eType==FUZZ_CHANGE_TYPE
   638    674          || pChange->eType==FUZZ_CHANGE_FIELD
          675  +       || pChange->eType==FUZZ_CHANGE_INDIRECT
          676  +       || pChange->eType==FUZZ_GROUP_DUP
          677  +       || pChange->eType==FUZZ_GROUP_DEL
          678  +       || pChange->eType==FUZZ_GROUP_SWAP
          679  +       || pChange->eType==FUZZ_COLUMN_ADD
          680  +       || pChange->eType==FUZZ_COLUMN_ADDPK
          681  +       || pChange->eType==FUZZ_COLUMN_DEL
   639    682     );
   640    683   
          684  +  pChange->iGroup = fuzzRandomInt(pParse->nGroup);
   641    685     pChange->iChange = fuzzRandomInt(pParse->nChange);
   642    686     if( pChange->eType==FUZZ_CHANGE_FIELD ){
   643    687       if( pParse->nUpdate==0 ) return -1;
   644    688       pChange->iChange = fuzzRandomInt(pParse->nUpdate);
   645    689     }
          690  +
          691  +  pChange->iDelete = -1;
          692  +  if( pChange->eType==FUZZ_COLUMN_DEL ){
          693  +    FuzzChangesetGroup *pGrp = pParse->apGroup[pChange->iGroup];
          694  +    int i;
          695  +    pChange->iDelete = fuzzRandomInt(pGrp->nCol);
          696  +    for(i=pGrp->nCol-1; i>=0; i--){
          697  +      if( pGrp->aPK[i] && pChange->iDelete!=i ) break;
          698  +    }
          699  +    if( i<0 ) return -1;
          700  +  }
          701  +
          702  +  if( pChange->eType==FUZZ_GROUP_SWAP ){
          703  +    FuzzChangesetGroup *pGrp;
          704  +    int iGrp = pChange->iGroup;
          705  +    if( pParse->nGroup==1 ) return -1;
          706  +    while( iGrp==pChange->iGroup ){
          707  +      iGrp = fuzzRandomInt(pParse->nGroup);
          708  +    }
          709  +    pGrp = pParse->apGroup[pChange->iGroup];
          710  +    pParse->apGroup[pChange->iGroup] = pParse->apGroup[iGrp];
          711  +    pParse->apGroup[iGrp] = pGrp;
          712  +  }
   646    713   
   647    714     if( pChange->eType==FUZZ_VALUE_SUB 
   648    715      || pChange->eType==FUZZ_VALUE_MOD 
   649    716      || pChange->eType==FUZZ_VALUE_RND 
   650    717     ){
   651    718       iSub = fuzzRandomInt(pParse->nVal);
   652         -    pChange->pSub1 = pParse->aVal[iSub];
          719  +    pChange->pSub1 = pParse->apVal[iSub];
   653    720       if( pChange->eType==FUZZ_VALUE_SUB ){
   654    721         iSub = fuzzRandomInt(pParse->nVal);
   655         -      pChange->pSub2 = pParse->aVal[iSub];
          722  +      pChange->pSub2 = pParse->apVal[iSub];
   656    723       }else{
   657    724         pChange->pSub2 = pChange->aSub;
   658    725       }
   659    726   
   660    727       if( pChange->eType==FUZZ_VALUE_RND ){
   661    728         pChange->aSub[0] = (u8)(fuzzRandomInt(5) + 1);
   662    729         switch( pChange->aSub[0] ){
................................................................................
   720    787     }
   721    788   
   722    789     return SQLITE_OK;
   723    790   }
   724    791   
   725    792   static int fuzzCopyChange(
   726    793     FuzzChangeset *pParse,
   727         -  FuzzChangesetGroup *pGrp, 
          794  +  int iGrp,
   728    795     FuzzChange *pFuzz,
   729    796     u8 **pp, u8 **ppOut             /* IN/OUT: Input and output pointers */
   730    797   ){
          798  +  FuzzChangesetGroup *pGrp = pParse->apGroup[iGrp];
   731    799     u8 *p = *pp;
   732    800     u8 *pOut = *ppOut;
   733    801     u8 eType = p++[0];
   734    802     int iRec;
   735    803     int nRec = (eType==SQLITE_UPDATE ? 2 : 1);
   736    804     int iUndef = -1;
          805  +  int nUpdate = 0;
   737    806   
   738    807     u8 eNew = eType;
   739    808     if( pFuzz->iCurrent==pFuzz->iChange && pFuzz->eType==FUZZ_CHANGE_TYPE ){
   740    809       switch( eType ){
   741    810         case SQLITE_INSERT:
   742    811           eNew = SQLITE_DELETE;
   743    812           break;
................................................................................
   770    839           nDef--;
   771    840         }
   772    841         fuzzChangeSize(pCsr, &sz);
   773    842         pCsr += sz;
   774    843       }
   775    844     }
   776    845   
   777         -  /* Copy the change type and indirect flag */
          846  +  /* Copy the change type and indirect flag. If the fuzz mode is
          847  +  ** FUZZ_CHANGE_INDIRECT, and the current change is the one selected for
          848  +  ** fuzzing, invert the indirect flag.  */
   778    849     *(pOut++) = eNew;
   779         -  *(pOut++) = *(p++);
          850  +  if( pFuzz->eType==FUZZ_CHANGE_INDIRECT && pFuzz->iCurrent==pFuzz->iChange ){
          851  +    *(pOut++) = !(*(p++));
          852  +  }else{
          853  +    *(pOut++) = *(p++);
          854  +  }
          855  +
   780    856     for(iRec=0; iRec<nRec; iRec++){
   781    857       int i;
   782    858       for(i=0; i<pGrp->nCol; i++){
   783    859         int sz;
   784    860         u8 *pCopy = p;
   785    861   
   786    862         if( p==pFuzz->pSub1 ){
................................................................................
   789    865           pCopy = pFuzz->pSub1;
   790    866         }else if( i==iUndef ){
   791    867           pCopy = "\0";
   792    868         }
   793    869   
   794    870         if( pCopy[0]==0x00 && eNew!=eType && eType==SQLITE_UPDATE && iRec==0 ){
   795    871           while( pCopy[0]==0x00 ){
   796         -          pCopy = pParse->aVal[fuzzRandomInt(pParse->nVal)];
          872  +          pCopy = pParse->apVal[fuzzRandomInt(pParse->nVal)];
   797    873           }
   798    874         }else if( p[0]==0x00 && pCopy[0]!=0x00 ){
   799    875           return -1;
   800    876         }else{
   801    877           if( pGrp->aPK[i]>0 && pCopy[0]==0x05 ) return -1;
   802    878         }
   803    879   
   804         -      if( eNew==eType || eType!=SQLITE_UPDATE || iRec==0 ){
   805         -        fuzzChangeSize(pCopy, &sz);
   806         -        memcpy(pOut, pCopy, sz);
   807         -        pOut += sz;
          880  +      if( pFuzz->iGroup!=iGrp || i!=pFuzz->iDelete ){
          881  +        if( eNew==eType || eType!=SQLITE_UPDATE || iRec==0 ){
          882  +          fuzzChangeSize(pCopy, &sz);
          883  +          memcpy(pOut, pCopy, sz);
          884  +          pOut += sz;
          885  +          nUpdate += (pGrp->aPK[i]==0 && pCopy[0]!=0x00);
          886  +        }
   808    887         }
   809    888   
   810    889         fuzzChangeSize(p, &sz);
   811    890         p += sz;
   812    891       }
          892  +
          893  +    if( iGrp==pFuzz->iGroup ){
          894  +      if( pFuzz->eType==FUZZ_COLUMN_ADD ){
          895  +        *(pOut++) = 0x05;
          896  +      }else if( pFuzz->eType==FUZZ_COLUMN_ADDPK ){
          897  +        if( iRec==1 ){
          898  +          *(pOut++) = 0x00;
          899  +        }else{
          900  +          u8 *pNew;
          901  +          int szNew;
          902  +          do {
          903  +            pNew = pParse->apVal[fuzzRandomInt(pParse->nVal)];
          904  +          }while( pNew[0]==0x00 || pNew[0]==0x05 );
          905  +          fuzzChangeSize(pNew, &szNew);
          906  +          memcpy(pOut, pNew, szNew);
          907  +          pOut += szNew;
          908  +        }
          909  +      }
          910  +    }
   813    911     }
   814    912   
   815    913     if( pFuzz->iCurrent==pFuzz->iChange ){
   816    914       if( pFuzz->eType==FUZZ_CHANGE_DUP ){
   817    915         int nByte = pOut - (*ppOut);
   818    916         memcpy(pOut, *ppOut, nByte);
   819    917         pOut += nByte;
   820    918       }
          919  +
   821    920       if( pFuzz->eType==FUZZ_CHANGE_DEL ){
   822         -      if( pGrp->nChange==1 ) return -1;
   823    921         pOut = *ppOut;
   824    922       }
   825    923       if( eNew!=eType && eNew==SQLITE_UPDATE ){
   826    924         int i;
   827    925         u8 *pCsr = (*ppOut) + 2;
   828    926         for(i=0; i<pGrp->nCol; i++){
   829    927           int sz;
................................................................................
   833    931           memcpy(pOut, pCopy, sz);
   834    932           pOut += sz;
   835    933           fuzzChangeSize(pCsr, &sz);
   836    934           pCsr += sz;
   837    935         }
   838    936       }
   839    937     }
          938  +
          939  +  /* If a column is being deleted from this group, and this change was an 
          940  +  ** UPDATE, and there are now no non-PK, non-undefined columns in the 
          941  +  ** change, remove it altogether. */
          942  +  if( pFuzz->eType==FUZZ_COLUMN_DEL && pFuzz->iGroup==iGrp 
          943  +   && eType==SQLITE_UPDATE && nUpdate==0 
          944  +  ){
          945  +    pOut = *ppOut;
          946  +  }
   840    947   
   841    948     *pp = p;
   842    949     *ppOut = pOut;
   843    950     pFuzz->iCurrent += (eType==SQLITE_UPDATE || pFuzz->eType!=FUZZ_CHANGE_FIELD);
   844    951     return SQLITE_OK;
   845    952   }
   846    953   
................................................................................
   855    962   
   856    963     while( rc<0 ){
   857    964       u8 *pOut = pBuf;
   858    965       rc = fuzzSelectChange(pParse, &change);
   859    966       for(iGrp=0; rc==SQLITE_OK && iGrp<pParse->nGroup; iGrp++){
   860    967         FuzzChangesetGroup *pGrp = pParse->apGroup[iGrp];
   861    968         int nTab = strlen(pGrp->zTab) + 1;
   862         -      u8 *p;
   863         -      int i;
          969  +      int j;
          970  +      int nRep = 1;
          971  +
          972  +      /* If this is the group to delete for a FUZZ_GROUP_DEL change, jump to
          973  +      ** the next group. Unless this is the only group in the changeset - in
          974  +      ** that case this change cannot be applied.
          975  +      **
          976  +      ** Or, if this is a FUZZ_GROUP_DUP, set nRep to 2 to output two
          977  +      ** copies of the group. */
          978  +      if( change.iGroup==iGrp ){
          979  +        if( change.eType==FUZZ_GROUP_DEL ){
          980  +          if( pParse->nGroup==1 ) rc = -1;
          981  +          continue;
          982  +        }
          983  +        else if( change.eType==FUZZ_GROUP_DUP ){
          984  +          nRep = 2;
          985  +        }
          986  +      }
          987  +
          988  +      for(j=0; j<nRep; j++){
          989  +        int i;
          990  +        u8 *pSaved;
          991  +        u8 *p = pGrp->aChange;
          992  +        int nCol = pGrp->nCol;
          993  +        int iPKDel = 0;
          994  +        if( iGrp==change.iGroup ){
          995  +          if( change.eType==FUZZ_COLUMN_ADD 
          996  +           || change.eType==FUZZ_COLUMN_ADDPK 
          997  +          ){
          998  +            nCol++;
          999  +          }else if( change.eType==FUZZ_COLUMN_DEL ){
         1000  +            nCol--;
         1001  +            iPKDel = pGrp->aPK[change.iDelete];
         1002  +          }
         1003  +        }
         1004  +
         1005  +        /* Output a table header */
         1006  +        pOut++[0] = 'T';
         1007  +        pOut += fuzzPutVarint(pOut, nCol);
   864   1008   
   865         -      /* Output a table header */
   866         -      pOut++[0] = 'T';
   867         -      pOut += fuzzPutVarint(pOut, pGrp->nCol);
   868         -      memcpy(pOut, pGrp->aPK, pGrp->nCol);
   869         -      pOut += pGrp->nCol;
   870         -      memcpy(pOut, pGrp->zTab, nTab);
   871         -      pOut += nTab;
         1009  +        for(i=0; i<pGrp->nCol; i++){
         1010  +          if( iGrp!=change.iGroup || i!=change.iDelete ){
         1011  +            u8 v = pGrp->aPK[i];
         1012  +            if( iPKDel && v>iPKDel ) v--;
         1013  +            *(pOut++) = v;
         1014  +          }
         1015  +        }
         1016  +        if( nCol>pGrp->nCol ){
         1017  +          if( change.eType==FUZZ_COLUMN_ADD ){
         1018  +            *(pOut++) = 0x00;
         1019  +          }else{
         1020  +            u8 max = 0;
         1021  +            for(i=0; i<pGrp->nCol; i++){
         1022  +              if( pGrp->aPK[i]>max ) max = pGrp->aPK[i];
         1023  +            }
         1024  +            *(pOut++) = max+1;
         1025  +          }
         1026  +        }
         1027  +        memcpy(pOut, pGrp->zTab, nTab);
         1028  +        pOut += nTab;
   872   1029   
   873         -      /* Output the change array */
   874         -      p = pGrp->aChange;
   875         -      for(i=0; rc==SQLITE_OK && i<pGrp->nChange; i++){
   876         -        rc = fuzzCopyChange(pParse, pGrp, &change, &p, &pOut);
         1030  +        /* Output the change array. */
         1031  +        pSaved = pOut;
         1032  +        for(i=0; rc==SQLITE_OK && i<pGrp->nChange; i++){
         1033  +          rc = fuzzCopyChange(pParse, iGrp, &change, &p, &pOut);
         1034  +        }
         1035  +        if( pOut==pSaved ) rc = -1;
   877   1036         }
   878   1037       }
   879   1038       if( rc==SQLITE_OK ){
   880   1039         fuzzWriteFile(zOut, pBuf, pOut-pBuf);
   881   1040       }
   882   1041     }
   883   1042   
................................................................................
   912   1071           rc = SQLITE_NOMEM;
   913   1072         }else{
   914   1073           iSeed = atoi(argv[2]);
   915   1074           nRepeat = atoi(argv[3]);
   916   1075           fuzzRandomSeed((unsigned int)iSeed);
   917   1076           for(i=0; rc==SQLITE_OK && i<nRepeat; i++){
   918   1077             char *zOut = sqlite3_mprintf("%s-%d", zInput, i);
   919         -          fuzzDoOneFuzz(zOut, pBuf, &changeset);
         1078  +          rc = fuzzDoOneFuzz(zOut, pBuf, &changeset);
   920   1079             sqlite3_free(zOut);
   921   1080           }
   922   1081           fuzzFree(pBuf);
   923   1082         }
   924   1083       }
   925   1084     }
   926   1085   
   927   1086     if( rc!=SQLITE_OK ){
   928   1087       fprintf(stderr, "error while processing changeset: %d\n", rc);
   929   1088     }
         1089  +
   930   1090     return rc;
   931   1091   }
   932   1092