| Index: third_party/sqlite/src/tool/showwal.c | 
| diff --git a/third_party/sqlite/src/tool/showwal.c b/third_party/sqlite/src/tool/showwal.c | 
| index ae25a59f9a2e5d0492d552704ec1d604c38e20ce..35810c66a96ff875612068bf179995f43279ff77 100644 | 
| --- a/third_party/sqlite/src/tool/showwal.c | 
| +++ b/third_party/sqlite/src/tool/showwal.c | 
| @@ -6,7 +6,13 @@ | 
| #include <sys/types.h> | 
| #include <sys/stat.h> | 
| #include <fcntl.h> | 
| + | 
| +#if !defined(_MSC_VER) | 
| #include <unistd.h> | 
| +#else | 
| +#include <io.h> | 
| +#endif | 
| + | 
| #include <stdlib.h> | 
| #include <string.h> | 
|  | 
| @@ -18,6 +24,65 @@ static int perLine = 16;        /* HEX elements to print per line */ | 
|  | 
| typedef long long int i64;      /* Datatype for 64-bit integers */ | 
|  | 
| +/* Information for computing the checksum */ | 
| +typedef struct Cksum Cksum; | 
| +struct Cksum { | 
| +  int bSwap;           /* True to do byte swapping on 32-bit words */ | 
| +  unsigned s0, s1;     /* Current checksum value */ | 
| +}; | 
| + | 
| +/* | 
| +** extract a 32-bit big-endian integer | 
| +*/ | 
| +static unsigned int getInt32(const unsigned char *a){ | 
| +  unsigned int x = (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3]; | 
| +  return x; | 
| +} | 
| + | 
| +/* | 
| +** Swap bytes on a 32-bit unsigned integer | 
| +*/ | 
| +static unsigned int swab32(unsigned int x){ | 
| +  return (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) | 
| +         + (((x)&0x00FF0000)>>8)  + (((x)&0xFF000000)>>24); | 
| +} | 
| + | 
| +/* Extend the checksum.  Reinitialize the checksum if bInit is true. | 
| +*/ | 
| +static void extendCksum( | 
| +  Cksum *pCksum, | 
| +  unsigned char *aData, | 
| +  unsigned int nByte, | 
| +  int bInit | 
| +){ | 
| +  unsigned int *a32; | 
| +  if( bInit ){ | 
| +    int a = 0; | 
| +    *((char*)&a) = 1; | 
| +    if( a==1 ){ | 
| +      /* Host is little-endian */ | 
| +      pCksum->bSwap = getInt32(aData)!=0x377f0682; | 
| +    }else{ | 
| +      /* Host is big-endian */ | 
| +      pCksum->bSwap = getInt32(aData)!=0x377f0683; | 
| +    } | 
| +    pCksum->s0 = 0; | 
| +    pCksum->s1 = 0; | 
| +  } | 
| +  a32 = (unsigned int*)aData; | 
| +  while( nByte>0 ){ | 
| +    unsigned int x0 = a32[0]; | 
| +    unsigned int x1 = a32[1]; | 
| +    if( pCksum->bSwap ){ | 
| +      x0 = swab32(x0); | 
| +      x1 = swab32(x1); | 
| +    } | 
| +    pCksum->s0 += x0 + pCksum->s1; | 
| +    pCksum->s1 += x1 + pCksum->s0; | 
| +    nByte -= 8; | 
| +    a32 += 2; | 
| +  } | 
| +} | 
|  | 
| /* | 
| ** Convert the var-int format into i64.  Return the number of bytes | 
| @@ -113,7 +178,7 @@ static void print_decode_line( | 
| int val = aData[ofst]; | 
| char zBuf[100]; | 
| sprintf(zBuf, " %03x: %02x", ofst, aData[ofst]); | 
| -  i = strlen(zBuf); | 
| +  i = (int)strlen(zBuf); | 
| for(j=1; j<4; j++){ | 
| if( j>=nByte ){ | 
| sprintf(&zBuf[i], "   "); | 
| @@ -121,7 +186,7 @@ static void print_decode_line( | 
| sprintf(&zBuf[i], " %02x", aData[ofst+j]); | 
| val = val*256 + aData[ofst+j]; | 
| } | 
| -    i += strlen(&zBuf[i]); | 
| +    i += (int)strlen(&zBuf[i]); | 
| } | 
| if( asHex ){ | 
| sprintf(&zBuf[i], "  0x%08x", val); | 
| @@ -152,39 +217,46 @@ static void print_frame(int iFrame){ | 
| } | 
|  | 
| /* | 
| -** extract a 32-bit big-endian integer | 
| -*/ | 
| -static unsigned int getInt32(const unsigned char *a){ | 
| -  unsigned int x = (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3]; | 
| -  return x; | 
| -} | 
| - | 
| -/* | 
| -** Print an entire page of content as hex | 
| +** Summarize a single frame on a single line. | 
| */ | 
| -static void print_oneline_frame(int iFrame){ | 
| +static void print_oneline_frame(int iFrame, Cksum *pCksum){ | 
| int iStart; | 
| unsigned char *aData; | 
| +  unsigned int s0, s1; | 
| iStart = 32 + (iFrame-1)*(pagesize+24); | 
| aData = getContent(iStart, 24); | 
| -  fprintf(stdout, "Frame %4d: %6d %6d 0x%08x 0x%08x 0x%08x 0x%08x\n", | 
| +  extendCksum(pCksum, aData, 8, 0); | 
| +  extendCksum(pCksum, getContent(iStart+24, pagesize), pagesize, 0); | 
| +  s0 = getInt32(aData+16); | 
| +  s1 = getInt32(aData+20); | 
| +  fprintf(stdout, "Frame %4d: %6d %6d 0x%08x,%08x 0x%08x,%08x %s\n", | 
| iFrame, | 
| getInt32(aData), | 
| getInt32(aData+4), | 
| getInt32(aData+8), | 
| getInt32(aData+12), | 
| -          getInt32(aData+16), | 
| -          getInt32(aData+20) | 
| +          s0, | 
| +          s1, | 
| +          (s0==pCksum->s0 && s1==pCksum->s1) ? "" : "cksum-fail" | 
| ); | 
| + | 
| +  /* Reset the checksum so that a single frame checksum failure will not | 
| +  ** cause all subsequent frames to also show a failure. */ | 
| +  pCksum->s0 = s0; | 
| +  pCksum->s1 = s1; | 
| free(aData); | 
| } | 
|  | 
| /* | 
| ** Decode the WAL header. | 
| */ | 
| -static void print_wal_header(void){ | 
| +static void print_wal_header(Cksum *pCksum){ | 
| unsigned char *aData; | 
| aData = getContent(0, 32); | 
| +  if( pCksum ){ | 
| +    extendCksum(pCksum, aData, 24, 1); | 
| +    printf("Checksum byte order: %s\n", pCksum->bSwap ? "swapped" : "native"); | 
| +  } | 
| printf("WAL Header:\n"); | 
| print_decode_line(aData, 0, 4,1,"Magic.  0x377f0682 (le) or 0x377f0683 (be)"); | 
| print_decode_line(aData, 4, 4, 0, "File format"); | 
| @@ -194,60 +266,199 @@ static void print_wal_header(void){ | 
| print_decode_line(aData, 20,4, 1, "Salt-2"); | 
| print_decode_line(aData, 24,4, 1, "Checksum-1"); | 
| print_decode_line(aData, 28,4, 1, "Checksum-2"); | 
| +  if( pCksum ){ | 
| +    if( pCksum->s0!=getInt32(aData+24) ){ | 
| +      printf("**** cksum-1 mismatch: 0x%08x\n", pCksum->s0); | 
| +    } | 
| +    if( pCksum->s1!=getInt32(aData+28) ){ | 
| +      printf("**** cksum-2 mismatch: 0x%08x\n", pCksum->s1); | 
| +    } | 
| +  } | 
| free(aData); | 
| } | 
| +/* | 
| +** Describe cell content. | 
| +*/ | 
| +static i64 describeContent( | 
| +  unsigned char *a,       /* Cell content */ | 
| +  i64 nLocal,             /* Bytes in a[] */ | 
| +  char *zDesc             /* Write description here */ | 
| +){ | 
| +  int nDesc = 0; | 
| +  int n, j; | 
| +  i64 i, x, v; | 
| +  const unsigned char *pData; | 
| +  const unsigned char *pLimit; | 
| +  char sep = ' '; | 
| + | 
| +  pLimit = &a[nLocal]; | 
| +  n = decodeVarint(a, &x); | 
| +  pData = &a[x]; | 
| +  a += n; | 
| +  i = x - n; | 
| +  while( i>0 && pData<=pLimit ){ | 
| +    n = decodeVarint(a, &x); | 
| +    a += n; | 
| +    i -= n; | 
| +    nLocal -= n; | 
| +    zDesc[0] = sep; | 
| +    sep = ','; | 
| +    nDesc++; | 
| +    zDesc++; | 
| +    if( x==0 ){ | 
| +      sprintf(zDesc, "*");     /* NULL is a "*" */ | 
| +    }else if( x>=1 && x<=6 ){ | 
| +      v = (signed char)pData[0]; | 
| +      pData++; | 
| +      switch( x ){ | 
| +        case 6:  v = (v<<16) + (pData[0]<<8) + pData[1];  pData += 2; | 
| +        case 5:  v = (v<<16) + (pData[0]<<8) + pData[1];  pData += 2; | 
| +        case 4:  v = (v<<8) + pData[0];  pData++; | 
| +        case 3:  v = (v<<8) + pData[0];  pData++; | 
| +        case 2:  v = (v<<8) + pData[0];  pData++; | 
| +      } | 
| +      sprintf(zDesc, "%lld", v); | 
| +    }else if( x==7 ){ | 
| +      sprintf(zDesc, "real"); | 
| +      pData += 8; | 
| +    }else if( x==8 ){ | 
| +      sprintf(zDesc, "0"); | 
| +    }else if( x==9 ){ | 
| +      sprintf(zDesc, "1"); | 
| +    }else if( x>=12 ){ | 
| +      i64 size = (x-12)/2; | 
| +      if( (x&1)==0 ){ | 
| +        sprintf(zDesc, "blob(%lld)", size); | 
| +      }else{ | 
| +        sprintf(zDesc, "txt(%lld)", size); | 
| +      } | 
| +      pData += size; | 
| +    } | 
| +    j = (int)strlen(zDesc); | 
| +    zDesc += j; | 
| +    nDesc += j; | 
| +  } | 
| +  return nDesc; | 
| +} | 
| + | 
| +/* | 
| +** Compute the local payload size given the total payload size and | 
| +** the page size. | 
| +*/ | 
| +static i64 localPayload(i64 nPayload, char cType){ | 
| +  i64 maxLocal; | 
| +  i64 minLocal; | 
| +  i64 surplus; | 
| +  i64 nLocal; | 
| +  if( cType==13 ){ | 
| +    /* Table leaf */ | 
| +    maxLocal = pagesize-35; | 
| +    minLocal = (pagesize-12)*32/255-23; | 
| +  }else{ | 
| +    maxLocal = (pagesize-12)*64/255-23; | 
| +    minLocal = (pagesize-12)*32/255-23; | 
| +  } | 
| +  if( nPayload>maxLocal ){ | 
| +    surplus = minLocal + (nPayload-minLocal)%(pagesize-4); | 
| +    if( surplus<=maxLocal ){ | 
| +      nLocal = surplus; | 
| +    }else{ | 
| +      nLocal = minLocal; | 
| +    } | 
| +  }else{ | 
| +    nLocal = nPayload; | 
| +  } | 
| +  return nLocal; | 
| +} | 
|  | 
| /* | 
| ** Create a description for a single cell. | 
| +** | 
| +** The return value is the local cell size. | 
| */ | 
| -static int describeCell(unsigned char cType, unsigned char *a, char **pzDesc){ | 
| +static i64 describeCell( | 
| +  unsigned char cType,    /* Page type */ | 
| +  unsigned char *a,       /* Cell content */ | 
| +  int showCellContent,    /* Show cell content if true */ | 
| +  char **pzDesc           /* Store description here */ | 
| +){ | 
| int i; | 
| -  int nDesc = 0; | 
| +  i64 nDesc = 0; | 
| int n = 0; | 
| int leftChild; | 
| i64 nPayload; | 
| i64 rowid; | 
| -  static char zDesc[100]; | 
| +  i64 nLocal; | 
| +  static char zDesc[1000]; | 
| i = 0; | 
| if( cType<=5 ){ | 
| leftChild = ((a[0]*256 + a[1])*256 + a[2])*256 + a[3]; | 
| a += 4; | 
| n += 4; | 
| -    sprintf(zDesc, "left-child: %d ", leftChild); | 
| +    sprintf(zDesc, "lx: %d ", leftChild); | 
| nDesc = strlen(zDesc); | 
| } | 
| if( cType!=5 ){ | 
| i = decodeVarint(a, &nPayload); | 
| a += i; | 
| n += i; | 
| -    sprintf(&zDesc[nDesc], "sz: %lld ", nPayload); | 
| +    sprintf(&zDesc[nDesc], "n: %lld ", nPayload); | 
| nDesc += strlen(&zDesc[nDesc]); | 
| +    nLocal = localPayload(nPayload, cType); | 
| +  }else{ | 
| +    nPayload = nLocal = 0; | 
| } | 
| if( cType==5 || cType==13 ){ | 
| i = decodeVarint(a, &rowid); | 
| a += i; | 
| n += i; | 
| -    sprintf(&zDesc[nDesc], "rowid: %lld ", rowid); | 
| +    sprintf(&zDesc[nDesc], "r: %lld ", rowid); | 
| +    nDesc += strlen(&zDesc[nDesc]); | 
| +  } | 
| +  if( nLocal<nPayload ){ | 
| +    int ovfl; | 
| +    unsigned char *b = &a[nLocal]; | 
| +    ovfl = ((b[0]*256 + b[1])*256 + b[2])*256 + b[3]; | 
| +    sprintf(&zDesc[nDesc], "ov: %d ", ovfl); | 
| nDesc += strlen(&zDesc[nDesc]); | 
| +    n += 4; | 
| +  } | 
| +  if( showCellContent && cType!=5 ){ | 
| +    nDesc += describeContent(a, nLocal, &zDesc[nDesc-1]); | 
| } | 
| *pzDesc = zDesc; | 
| -  return n; | 
| +  return nLocal+n; | 
| } | 
|  | 
| /* | 
| ** Decode a btree page | 
| */ | 
| -static void decode_btree_page(unsigned char *a, int pgno, int hdrSize){ | 
| +static void decode_btree_page( | 
| +  unsigned char *a,   /* Content of the btree page to be decoded */ | 
| +  int pgno,           /* Page number */ | 
| +  int hdrSize,        /* Size of the page1-header in bytes */ | 
| +  const char *zArgs   /* Flags to control formatting */ | 
| +){ | 
| const char *zType = "unknown"; | 
| int nCell; | 
| -  int i; | 
| +  int i, j; | 
| int iCellPtr; | 
| +  int showCellContent = 0; | 
| +  int showMap = 0; | 
| +  char *zMap = 0; | 
| switch( a[0] ){ | 
| case 2:  zType = "index interior node";  break; | 
| case 5:  zType = "table interior node";  break; | 
| case 10: zType = "index leaf";           break; | 
| case 13: zType = "table leaf";           break; | 
| } | 
| +  while( zArgs[0] ){ | 
| +    switch( zArgs[0] ){ | 
| +      case 'c': showCellContent = 1;  break; | 
| +      case 'm': showMap = 1;          break; | 
| +    } | 
| +    zArgs++; | 
| +  } | 
| printf("Decode of btree page %d:\n", pgno); | 
| print_decode_line(a, 0, 1, 0, zType); | 
| print_decode_line(a, 1, 2, 0, "Offset to first freeblock"); | 
| @@ -261,18 +472,45 @@ static void decode_btree_page(unsigned char *a, int pgno, int hdrSize){ | 
| }else{ | 
| iCellPtr = 8; | 
| } | 
| +  if( nCell>0 ){ | 
| +    printf(" key: lx=left-child n=payload-size r=rowid\n"); | 
| +  } | 
| +  if( showMap ){ | 
| +    zMap = malloc(pagesize); | 
| +    memset(zMap, '.', pagesize); | 
| +    memset(zMap, '1', hdrSize); | 
| +    memset(&zMap[hdrSize], 'H', iCellPtr); | 
| +    memset(&zMap[hdrSize+iCellPtr], 'P', 2*nCell); | 
| +  } | 
| for(i=0; i<nCell; i++){ | 
| int cofst = iCellPtr + i*2; | 
| char *zDesc; | 
| +    i64 n; | 
| + | 
| cofst = a[cofst]*256 + a[cofst+1]; | 
| -    describeCell(a[0], &a[cofst-hdrSize], &zDesc); | 
| +    n = describeCell(a[0], &a[cofst-hdrSize], showCellContent, &zDesc); | 
| +    if( showMap ){ | 
| +      char zBuf[30]; | 
| +      memset(&zMap[cofst], '*', (size_t)n); | 
| +      zMap[cofst] = '['; | 
| +      zMap[cofst+n-1] = ']'; | 
| +      sprintf(zBuf, "%d", i); | 
| +      j = (int)strlen(zBuf); | 
| +      if( j<=n-2 ) memcpy(&zMap[cofst+1], zBuf, j); | 
| +    } | 
| printf(" %03x: cell[%d] %s\n", cofst, i, zDesc); | 
| } | 
| +  if( showMap ){ | 
| +    for(i=0; i<pagesize; i+=64){ | 
| +      printf(" %03x: %.64s\n", i, &zMap[i]); | 
| +    } | 
| +    free(zMap); | 
| +  } | 
| } | 
|  | 
| int main(int argc, char **argv){ | 
| struct stat sbuf; | 
| -  unsigned char zPgSz[2]; | 
| +  unsigned char zPgSz[4]; | 
| if( argc<2 ){ | 
| fprintf(stderr,"Usage: %s FILENAME ?PAGE? ...\n", argv[0]); | 
| exit(1); | 
| @@ -284,9 +522,9 @@ int main(int argc, char **argv){ | 
| } | 
| zPgSz[0] = 0; | 
| zPgSz[1] = 0; | 
| -  lseek(fd, 10, SEEK_SET); | 
| -  read(fd, zPgSz, 2); | 
| -  pagesize = zPgSz[0]*256 + zPgSz[1]; | 
| +  lseek(fd, 8, SEEK_SET); | 
| +  read(fd, zPgSz, 4); | 
| +  pagesize = zPgSz[1]*65536 + zPgSz[2]*256 + zPgSz[3]; | 
| if( pagesize==0 ) pagesize = 1024; | 
| printf("Pagesize: %d\n", pagesize); | 
| fstat(fd, &sbuf); | 
| @@ -298,15 +536,18 @@ int main(int argc, char **argv){ | 
| printf("Available pages: 1..%d\n", mxFrame); | 
| if( argc==2 ){ | 
| int i; | 
| -    print_wal_header(); | 
| -    for(i=1; i<=mxFrame; i++) print_oneline_frame(i); | 
| +    Cksum x; | 
| +    print_wal_header(&x); | 
| +    for(i=1; i<=mxFrame; i++){ | 
| +      print_oneline_frame(i, &x); | 
| +    } | 
| }else{ | 
| int i; | 
| for(i=2; i<argc; i++){ | 
| int iStart, iEnd; | 
| char *zLeft; | 
| if( strcmp(argv[i], "header")==0 ){ | 
| -        print_wal_header(); | 
| +        print_wal_header(0); | 
| continue; | 
| } | 
| if( !isdigit(argv[i][0]) ){ | 
| @@ -318,11 +559,11 @@ int main(int argc, char **argv){ | 
| iEnd = mxFrame; | 
| }else if( zLeft && zLeft[0]=='.' && zLeft[1]=='.' ){ | 
| iEnd = strtol(&zLeft[2], 0, 0); | 
| -#if 0 | 
| }else if( zLeft && zLeft[0]=='b' ){ | 
| int ofst, nByte, hdrSize; | 
| unsigned char *a; | 
| if( iStart==1 ){ | 
| +          hdrSize = 100; | 
| ofst = hdrSize = 100; | 
| nByte = pagesize-100; | 
| }else{ | 
| @@ -330,11 +571,11 @@ int main(int argc, char **argv){ | 
| ofst = (iStart-1)*pagesize; | 
| nByte = pagesize; | 
| } | 
| +        ofst = 32 + hdrSize + (iStart-1)*(pagesize+24) + 24; | 
| a = getContent(ofst, nByte); | 
| -        decode_btree_page(a, iStart, hdrSize); | 
| +        decode_btree_page(a, iStart, hdrSize, zLeft+1); | 
| free(a); | 
| continue; | 
| -#endif | 
| }else{ | 
| iEnd = iStart; | 
| } | 
|  |