/ Check-in [479b3d96]
Login

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

Overview
Comment:Binary file I/O infrastructure added and used to increase test coverage for detection of corrupt database files. (CVS 3822)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 479b3d965b19c3ec4cb72542718751debf8ff75c
User & Date: drh 2007-04-06 15:02:13
Context
2007-04-06
18:23
Additional coverage testing. (CVS 3823) check-in: 26b2e1ae user: drh tags: trunk
15:02
Binary file I/O infrastructure added and used to increase test coverage for detection of corrupt database files. (CVS 3822) check-in: 479b3d96 user: drh tags: trunk
11:26
The FOR EACH STATEMENT clause in a trigger is now a syntax error. It used to be silently ignored. STATEMENT is no longer a keyword. (CVS 3821) check-in: 8e2559b4 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to Makefile.in.

   218    218     $(TOP)/src/test5.c \
   219    219     $(TOP)/src/test6.c \
   220    220     $(TOP)/src/test7.c \
   221    221     $(TOP)/src/test8.c \
   222    222     $(TOP)/src/test9.c \
   223    223     $(TOP)/src/test_autoext.c \
   224    224     $(TOP)/src/test_async.c \
          225  +  $(TOP)/src/test_hexio.c \
   225    226     $(TOP)/src/test_md5.c \
   226    227     $(TOP)/src/test_schema.c \
   227    228     $(TOP)/src/test_server.c \
   228    229     $(TOP)/src/test_tclvar.c \
   229    230     $(TOP)/src/utf.c \
   230    231     $(TOP)/src/util.c \
   231    232     $(TOP)/src/vdbe.c \

Changes to main.mk.

   173    173     $(TOP)/src/test5.c \
   174    174     $(TOP)/src/test6.c \
   175    175     $(TOP)/src/test7.c \
   176    176     $(TOP)/src/test8.c \
   177    177     $(TOP)/src/test9.c \
   178    178     $(TOP)/src/test_autoext.c \
   179    179     $(TOP)/src/test_async.c \
          180  +  $(TOP)/src/test_hexio.c \
   180    181     $(TOP)/src/test_md5.c \
   181    182     $(TOP)/src/test_schema.c \
   182    183     $(TOP)/src/test_server.c \
   183    184     $(TOP)/src/test_tclvar.c \
   184    185     $(TOP)/src/utf.c \
   185    186     $(TOP)/src/util.c \
   186    187     $(TOP)/src/vdbe.c \

Changes to src/btree.c.

     5      5   ** a legal notice, here is a blessing:
     6      6   **
     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12         -** $Id: btree.c,v 1.351 2007/04/06 01:03:33 drh Exp $
           12  +** $Id: btree.c,v 1.352 2007/04/06 15:02:14 drh Exp $
    13     13   **
    14     14   ** This file implements a external (disk-based) database using BTrees.
    15     15   ** For a detailed discussion of BTrees, refer to
    16     16   **
    17     17   **     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
    18     18   **     "Sorting And Searching", pages 473-480. Addison-Wesley
    19     19   **     Publishing Company, Reading, Massachusetts.
................................................................................
  1866   1866       if( memcmp(page1, zMagicHeader, 16)!=0 ){
  1867   1867         goto page1_init_failed;
  1868   1868       }
  1869   1869       if( page1[18]>1 || page1[19]>1 ){
  1870   1870         goto page1_init_failed;
  1871   1871       }
  1872   1872       pageSize = get2byte(&page1[16]);
  1873         -    if( ((pageSize-1)&pageSize)!=0 ){
         1873  +    if( ((pageSize-1)&pageSize)!=0 || pageSize<512 ){
  1874   1874         goto page1_init_failed;
  1875   1875       }
  1876   1876       assert( (pageSize & 7)==0 );
  1877   1877       pBt->pageSize = pageSize;
  1878   1878       pBt->usableSize = pageSize - page1[20];
  1879   1879       if( pBt->usableSize<500 ){
  1880   1880         goto page1_init_failed;

Changes to src/parse.y.

    10     10   **
    11     11   *************************************************************************
    12     12   ** This file contains SQLite's grammar for SQL.  Process this file
    13     13   ** using the lemon parser generator to generate C code that runs
    14     14   ** the parser.  Lemon will also generate a header file containing
    15     15   ** numeric codes for all of the tokens.
    16     16   **
    17         -** @(#) $Id: parse.y,v 1.217 2007/04/06 11:26:00 drh Exp $
           17  +** @(#) $Id: parse.y,v 1.218 2007/04/06 15:02:14 drh Exp $
    18     18   */
    19     19   
    20     20   // All token codes are small integers with #defines that begin with "TK_"
    21     21   %token_prefix TK_
    22     22   
    23     23   // The type of the data attached to each token is Token.  This is also the
    24     24   // default type for non-terminals.
................................................................................
   538    538   
   539    539   %type having_opt {Expr*}
   540    540   %destructor having_opt {sqlite3ExprDelete($$);}
   541    541   having_opt(A) ::= .                {A = 0;}
   542    542   having_opt(A) ::= HAVING expr(X).  {A = X;}
   543    543   
   544    544   %type limit_opt {struct LimitVal}
   545         -%destructor limit_opt {
   546         -  sqlite3ExprDelete($$.pLimit);
   547         -  sqlite3ExprDelete($$.pOffset);
   548         -}
          545  +
          546  +// The destructor for limit_opt will never fire in the current grammar.
          547  +// The limit_opt non-terminal only occurs at the end of a single production
          548  +// rule for SELECT statements.  As soon as the rule that create the 
          549  +// limit_opt non-terminal reduces, the SELECT statement rule will also
          550  +// reduce.  So there is never a limit_opt non-terminal on the stack 
          551  +// except as a transient.  So there is never anything to destroy.
          552  +//
          553  +//%destructor limit_opt {
          554  +//  sqlite3ExprDelete($$.pLimit);
          555  +//  sqlite3ExprDelete($$.pOffset);
          556  +//}
   549    557   limit_opt(A) ::= .                     {A.pLimit = 0; A.pOffset = 0;}
   550    558   limit_opt(A) ::= LIMIT expr(X).        {A.pLimit = X; A.pOffset = 0;}
   551    559   limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y). 
   552    560                                          {A.pLimit = X; A.pOffset = Y;}
   553    561   limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y). 
   554    562                                          {A.pOffset = X; A.pLimit = Y;}
   555    563   

Changes to src/tclsqlite.c.

     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** A TCL Interface to SQLite.  Append this file to sqlite3.c and
    13     13   ** compile the whole thing to build a TCL-enabled version of SQLite.
    14     14   **
    15         -** $Id: tclsqlite.c,v 1.178 2007/04/05 21:58:33 drh Exp $
           15  +** $Id: tclsqlite.c,v 1.179 2007/04/06 15:02:14 drh Exp $
    16     16   */
    17     17   #include "tcl.h"
    18     18   
    19     19   /*
    20     20   ** Some additional include files are needed if this file is not
    21     21   ** appended to the amalgamation.
    22     22   */
................................................................................
  2214   2214       extern int Sqlitetest9_Init(Tcl_Interp*);
  2215   2215       extern int Md5_Init(Tcl_Interp*);
  2216   2216       extern int Sqlitetestsse_Init(Tcl_Interp*);
  2217   2217       extern int Sqlitetestasync_Init(Tcl_Interp*);
  2218   2218       extern int Sqlitetesttclvar_Init(Tcl_Interp*);
  2219   2219       extern int Sqlitetestschema_Init(Tcl_Interp*);
  2220   2220       extern int Sqlitetest_autoext_Init(Tcl_Interp*);
         2221  +    extern int Sqlitetest_hexio_Init(Tcl_Interp*);
  2221   2222   
  2222   2223       Sqlitetest1_Init(interp);
  2223   2224       Sqlitetest2_Init(interp);
  2224   2225       Sqlitetest3_Init(interp);
  2225   2226       Sqlitetest4_Init(interp);
  2226   2227       Sqlitetest5_Init(interp);
  2227   2228       Sqlitetest6_Init(interp);
................................................................................
  2228   2229       Sqlitetest7_Init(interp);
  2229   2230       Sqlitetest8_Init(interp);
  2230   2231       Sqlitetest9_Init(interp);
  2231   2232       Sqlitetestasync_Init(interp);
  2232   2233       Sqlitetesttclvar_Init(interp);
  2233   2234       Sqlitetestschema_Init(interp);
  2234   2235       Sqlitetest_autoext_Init(interp);
         2236  +    Sqlitetest_hexio_Init(interp);
  2235   2237       Md5_Init(interp);
  2236   2238   #ifdef SQLITE_SSE
  2237   2239       Sqlitetestsse_Init(interp);
  2238   2240   #endif
  2239   2241     }
  2240   2242   #endif
  2241   2243     if( argc>=2 || TCLSH==2 ){

Added src/test_hexio.c.

            1  +/*
            2  +** 2007 April 6
            3  +**
            4  +** The author disclaims copyright to this source code.  In place of
            5  +** a legal notice, here is a blessing:
            6  +**
            7  +**    May you do good and not evil.
            8  +**    May you find forgiveness for yourself and forgive others.
            9  +**    May you share freely, never taking more than you give.
           10  +**
           11  +*************************************************************************
           12  +** Code for testing all sorts of SQLite interfaces.  This code
           13  +** implements TCL commands for reading and writing the binary
           14  +** database files and displaying the content of those files as
           15  +** hexadecimal.  We could, in theory, use the built-in "binary"
           16  +** command of TCL to do a lot of this, but there are some issues
           17  +** with historical versions of the "binary" command.  So it seems
           18  +** easier and safer to build our own mechanism.
           19  +**
           20  +** $Id: test_hexio.c,v 1.1 2007/04/06 15:02:14 drh Exp $
           21  +*/
           22  +#include "tcl.h"
           23  +#include <stdlib.h>
           24  +#include <string.h>
           25  +#include <assert.h>
           26  +
           27  +/*
           28  +hexio_read  filename offset amt
           29  +hexio_write filename offset hexdata
           30  +hexio_get_int  hexdata
           31  +hexio_get_varint  hexdata
           32  +hexio_render_int8  integer
           33  +hexio_render_int16  integer
           34  +hexio_render_int38  integer
           35  +hexio_render_varint  integer
           36  +*/
           37  +
           38  +/*
           39  +** Convert binary to hex.  The input zBuf[] contains N bytes of
           40  +** binary data.  zBuf[] is 2*n+1 bytes long.  Overwrite zBuf[]
           41  +** with a hexadecimal representation of its original binary input.
           42  +*/
           43  +static void binToHex(unsigned char *zBuf, int N){
           44  +  const unsigned char zHex[] = "0123456789ABCDEF";
           45  +  int i, j;
           46  +  unsigned char c;
           47  +  i = N*2;
           48  +  zBuf[i--] = 0;
           49  +  for(j=N-1; j>=0; j--){
           50  +    c = zBuf[j];
           51  +    zBuf[i--] = zHex[c&0xf];
           52  +    zBuf[i--] = zHex[c>>4];
           53  +  }
           54  +  assert( i==-1 );
           55  +}
           56  +
           57  +/*
           58  +** Convert hex to binary.  The input zIn[] contains N bytes of
           59  +** hexadecimal.  Convert this into binary and write aOut[] with
           60  +** the binary data.  Spaces in the original input are ignored.
           61  +** Return the number of bytes of binary rendered.
           62  +*/
           63  +static int hexToBin(const unsigned char *zIn, int N, unsigned char *aOut){
           64  +  const unsigned char aMap[] = {
           65  +     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
           66  +     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
           67  +     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
           68  +     1, 2, 3, 4, 5, 6, 7, 8,  9,10, 0, 0, 0, 0, 0, 0,
           69  +     0,11,12,13,14,15,16, 0,  0, 0, 0, 0, 0, 0, 0, 0,
           70  +     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
           71  +     0,11,12,13,14,15,16, 0,  0, 0, 0, 0, 0, 0, 0, 0,
           72  +     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
           73  +     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
           74  +     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
           75  +     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
           76  +     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
           77  +     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
           78  +     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
           79  +     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
           80  +     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
           81  +  };
           82  +  int i, j;
           83  +  int hi=1;
           84  +  unsigned char c;
           85  +
           86  +  for(i=j=0; i<N; i++){
           87  +    c = aMap[zIn[i]];
           88  +    if( c==0 ) continue;
           89  +    if( hi ){
           90  +      aOut[j] = (c-1)<<4;
           91  +      hi = 0;
           92  +    }else{
           93  +      aOut[j++] |= c-1;
           94  +      hi = 1;
           95  +    }
           96  +  }
           97  +  return j;
           98  +}
           99  +
          100  +
          101  +/*
          102  +** Usage:   hexio_read  FILENAME  OFFSET  AMT
          103  +**
          104  +** Read AMT bytes from file FILENAME beginning at OFFSET from the
          105  +** beginning of the file.  Convert that information to hexadecimal
          106  +** and return the resulting HEX string.
          107  +*/
          108  +static int hexio_read(
          109  +  void * clientData,
          110  +  Tcl_Interp *interp,
          111  +  int objc,
          112  +  Tcl_Obj *CONST objv[]
          113  +){
          114  +  int offset;
          115  +  int amt, got;
          116  +  const char *zFile;
          117  +  unsigned char *zBuf;
          118  +  FILE *in;
          119  +
          120  +  if( objc!=4 ){
          121  +    Tcl_WrongNumArgs(interp, 1, objv, "FILENAME OFFSET AMT");
          122  +    return TCL_ERROR;
          123  +  }
          124  +  if( Tcl_GetIntFromObj(interp, objv[2], &offset) ) return TCL_ERROR;
          125  +  if( Tcl_GetIntFromObj(interp, objv[3], &amt) ) return TCL_ERROR;
          126  +  zFile = Tcl_GetString(objv[1]);
          127  +  zBuf = malloc( amt*2+1 );
          128  +  if( zBuf==0 ){
          129  +    return TCL_ERROR;
          130  +  }
          131  +  in = fopen(zFile, "r");
          132  +  if( in==0 ){
          133  +    Tcl_AppendResult(interp, "cannot open input file ", zFile, 0);
          134  +    return TCL_ERROR;
          135  +  }
          136  +  fseek(in, offset, SEEK_SET);
          137  +  got = fread(zBuf, 1, amt, in);
          138  +  fclose(in);
          139  +  if( got<0 ){
          140  +    got = 0;
          141  +  }
          142  +  binToHex(zBuf, got);
          143  +  Tcl_AppendResult(interp, zBuf, 0);
          144  +  free(zBuf);
          145  +  return TCL_OK;
          146  +}
          147  +
          148  +
          149  +/*
          150  +** Usage:   hexio_write  FILENAME  OFFSET  DATA
          151  +**
          152  +** Write DATA into file FILENAME beginning at OFFSET from the
          153  +** beginning of the file.  DATA is expressed in hexadecimal.
          154  +*/
          155  +static int hexio_write(
          156  +  void * clientData,
          157  +  Tcl_Interp *interp,
          158  +  int objc,
          159  +  Tcl_Obj *CONST objv[]
          160  +){
          161  +  int offset;
          162  +  int nIn, nOut, written;
          163  +  const char *zFile;
          164  +  const unsigned char *zIn;
          165  +  unsigned char *aOut;
          166  +  FILE *out;
          167  +
          168  +  if( objc!=4 ){
          169  +    Tcl_WrongNumArgs(interp, 1, objv, "FILENAME OFFSET HEXDATA");
          170  +    return TCL_ERROR;
          171  +  }
          172  +  if( Tcl_GetIntFromObj(interp, objv[2], &offset) ) return TCL_ERROR;
          173  +  zFile = Tcl_GetString(objv[1]);
          174  +  zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[3], &nIn);
          175  +  aOut = malloc( nIn/2 );
          176  +  if( aOut==0 ){
          177  +    return TCL_ERROR;
          178  +  }
          179  +  nOut = hexToBin(zIn, nIn, aOut);
          180  +  out = fopen(zFile, "r+");
          181  +  if( out==0 ){
          182  +    Tcl_AppendResult(interp, "cannot open output file ", zFile, 0);
          183  +    return TCL_ERROR;
          184  +  }
          185  +  fseek(out, offset, SEEK_SET);
          186  +  written = fwrite(aOut, 1, nOut, out);
          187  +  free(aOut);
          188  +  fclose(out);
          189  +  Tcl_SetObjResult(interp, Tcl_NewIntObj(written));
          190  +  return TCL_OK;
          191  +}
          192  +
          193  +/*
          194  +** USAGE:   hexio_get_int   HEXDATA
          195  +**
          196  +** Interpret the HEXDATA argument as a big-endian integer.  Return
          197  +** the value of that integer.  HEXDATA can contain between 2 and 8
          198  +** hexadecimal digits.
          199  +*/
          200  +static int hexio_get_int(
          201  +  void * clientData,
          202  +  Tcl_Interp *interp,
          203  +  int objc,
          204  +  Tcl_Obj *CONST objv[]
          205  +){
          206  +  int val;
          207  +  int nIn, nOut;
          208  +  const unsigned char *zIn;
          209  +  unsigned char *aOut;
          210  +  unsigned char aNum[4];
          211  +
          212  +  if( objc!=2 ){
          213  +    Tcl_WrongNumArgs(interp, 1, objv, "HEXDATA");
          214  +    return TCL_ERROR;
          215  +  }
          216  +  zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[1], &nIn);
          217  +  aOut = malloc( nIn/2 );
          218  +  if( aOut==0 ){
          219  +    return TCL_ERROR;
          220  +  }
          221  +  nOut = hexToBin(zIn, nIn, aOut);
          222  +  if( nOut>=4 ){
          223  +    memcpy(aNum, aOut, 4);
          224  +  }else{
          225  +    memset(aNum, 0, sizeof(aNum));
          226  +    memcpy(&aNum[4-nOut], aOut, 4-nOut);
          227  +  }
          228  +  free(aOut);
          229  +  val = (aNum[0]<<24) | (aNum[1]<<16) | (aNum[2]<<8) | aNum[3];
          230  +  Tcl_SetObjResult(interp, Tcl_NewIntObj(val));
          231  +  return TCL_OK;
          232  +}
          233  +
          234  +
          235  +/*
          236  +** USAGE:   hexio_render_int16   INTEGER
          237  +**
          238  +** Render INTEGER has a 16-bit big-endian integer in hexadecimal.
          239  +*/
          240  +static int hexio_render_int16(
          241  +  void * clientData,
          242  +  Tcl_Interp *interp,
          243  +  int objc,
          244  +  Tcl_Obj *CONST objv[]
          245  +){
          246  +  int val;
          247  +  unsigned char aNum[10];
          248  +
          249  +  if( objc!=2 ){
          250  +    Tcl_WrongNumArgs(interp, 1, objv, "INTEGER");
          251  +    return TCL_ERROR;
          252  +  }
          253  +  if( Tcl_GetIntFromObj(interp, objv[1], &val) ) return TCL_ERROR;
          254  +  aNum[0] = val>>8;
          255  +  aNum[1] = val;
          256  +  binToHex(aNum, 2);
          257  +  Tcl_SetObjResult(interp, Tcl_NewStringObj((char*)aNum, 4));
          258  +  return TCL_OK;
          259  +}
          260  +
          261  +
          262  +/*
          263  +** USAGE:   hexio_render_int32   INTEGER
          264  +**
          265  +** Render INTEGER has a 32-bit big-endian integer in hexadecimal.
          266  +*/
          267  +static int hexio_render_int32(
          268  +  void * clientData,
          269  +  Tcl_Interp *interp,
          270  +  int objc,
          271  +  Tcl_Obj *CONST objv[]
          272  +){
          273  +  int val;
          274  +  unsigned char aNum[10];
          275  +
          276  +  if( objc!=2 ){
          277  +    Tcl_WrongNumArgs(interp, 1, objv, "INTEGER");
          278  +    return TCL_ERROR;
          279  +  }
          280  +  if( Tcl_GetIntFromObj(interp, objv[1], &val) ) return TCL_ERROR;
          281  +  aNum[0] = val>>24;
          282  +  aNum[1] = val>>16;
          283  +  aNum[2] = val>>8;
          284  +  aNum[3] = val;
          285  +  binToHex(aNum, 4);
          286  +  Tcl_SetObjResult(interp, Tcl_NewStringObj((char*)aNum, 8));
          287  +  return TCL_OK;
          288  +}
          289  +
          290  +
          291  +
          292  +/*
          293  +** Register commands with the TCL interpreter.
          294  +*/
          295  +int Sqlitetest_hexio_Init(Tcl_Interp *interp){
          296  +  static struct {
          297  +     char *zName;
          298  +     Tcl_ObjCmdProc *xProc;
          299  +  } aObjCmd[] = {
          300  +     { "hexio_read",                   hexio_read            },
          301  +     { "hexio_write",                  hexio_write           },
          302  +     { "hexio_get_int",                hexio_get_int         },
          303  +     { "hexio_render_int16",           hexio_render_int16    },
          304  +     { "hexio_render_int32",           hexio_render_int32    },
          305  +  };
          306  +  int i;
          307  +  for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
          308  +    Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
          309  +  }
          310  +  return TCL_OK;
          311  +}

Added test/corrupt3.test.

            1  +# 2007 April 6
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library.
           12  +#
           13  +# This file implements tests to make sure SQLite does not crash or
           14  +# segfault if it sees a corrupt database file.
           15  +#
           16  +# $Id: corrupt3.test,v 1.1 2007/04/06 15:02:14 drh Exp $
           17  +
           18  +set testdir [file dirname $argv0]
           19  +source $testdir/tester.tcl
           20  +
           21  +# We must have the page_size pragma for these tests to work.
           22  +#
           23  +ifcapable !pager_pragmas {
           24  +  finish_test
           25  +  return
           26  +}
           27  +
           28  +# Create a database with an overflow page.
           29  +#
           30  +do_test corrupt3-1.1 {
           31  +  set bigstring [string repeat 0123456789 200]
           32  +  execsql {
           33  +    PRAGMA page_size=1024;
           34  +    CREATE TABLE t1(x);
           35  +    INSERT INTO t1 VALUES($bigstring);
           36  +  }
           37  +  file size test.db
           38  +} [expr {1024*3}]
           39  +
           40  +# Verify that the file format is as we expect.  The page size
           41  +# should be 1024 bytes.  The only record should have a single
           42  +# overflow page.  The overflow page is page 3.  The pointer to
           43  +# the overflow page is on the last 4 bytes of page 2.
           44  +#
           45  +do_test corrupt3-1.2 {
           46  +  hexio_get_int [hexio_read test.db 16 2]
           47  +} 1024   ;# The page size is 1024
           48  +do_test corrupt3-1.3 {
           49  +  hexio_get_int [hexio_read test.db 20 1]
           50  +} 0      ;# Unused bytes per page is 0
           51  +do_test corrupt3-1.4 {
           52  +  hexio_get_int [hexio_read test.db 2044 4]
           53  +} 3      ;# Overflow page is 3
           54  +do_test corrupt3-1.5 {
           55  +  hexio_get_int [hexio_read test.db 2048 4]
           56  +} 0      ;# First chained overflow is 0
           57  +
           58  +integrity_check corrupt3-1.6
           59  +
           60  +# Make the overflow chain loop back on itself.   See if the
           61  +# corruption is detected.   (Actually, the last pointer in
           62  +# an overflow chain is ignored, so this is not an error.)
           63  +#
           64  +do_test corrupt3-1.7 {
           65  +  db close
           66  +  hexio_write test.db 2048 [hexio_render_int32 3]
           67  +  sqlite3 db test.db
           68  +  catchsql {
           69  +    SELECT x FROM t1
           70  +  }
           71  +} [list 0 $bigstring]
           72  +integrity_check corrupt3-1.8
           73  +
           74  +# Change the pointer for the first page of the overflow
           75  +# change to be a non-existant page.
           76  +#
           77  +do_test corrupt3-1.9 {
           78  +  db close
           79  +  hexio_write test.db 2044 [hexio_render_int32 4]
           80  +  sqlite3 db test.db
           81  +  catchsql {
           82  +    SELECT substr(x,1,10) FROM t1
           83  +  }
           84  +} [list 0 0123456789]
           85  +do_test corrupt3-1.10 {
           86  +  catchsql {
           87  +    PRAGMA integrity_check
           88  +  }
           89  +} {0 {{*** in database main ***
           90  +On tree page 2 cell 0: invalid page number 4
           91  +Page 3 is never used}}}
           92  +do_test corrupt3-1.11 {
           93  +  db close
           94  +  hexio_write test.db 2044 [hexio_render_int32 0]
           95  +  sqlite3 db test.db
           96  +  catchsql {
           97  +    SELECT substr(x,1,10) FROM t1
           98  +  }
           99  +} [list 1 {database disk image is malformed}]
          100  +do_test corrupt3-1.12 {
          101  +  catchsql {
          102  +    PRAGMA integrity_check
          103  +  }
          104  +} {0 {{*** in database main ***
          105  +On tree page 2 cell 0: 1 of 1 pages missing from overflow list starting at 0
          106  +Page 3 is never used}}}
          107  +
          108  +finish_test

Added test/filefmt.test.

            1  +# 2007 April 6
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library.
           12  +#
           13  +# This file implements tests to verify database file format.
           14  +#
           15  +# $Id: filefmt.test,v 1.1 2007/04/06 15:02:14 drh Exp $
           16  +
           17  +set testdir [file dirname $argv0]
           18  +source $testdir/tester.tcl
           19  +db close
           20  +file delete -force test.db test.db-journal
           21  +
           22  +# Database begins with valid 16-byte header string.
           23  +#
           24  +do_test filefmt-1.1 {
           25  +  sqlite3 db test.db
           26  +  db eval {CREATE TABLE t1(x)}
           27  +  db close
           28  +  hexio_read test.db 0 16
           29  +} {53514C69746520666F726D6174203300}
           30  +
           31  +# If the 16-byte header is changed, the file will not open
           32  +#
           33  +do_test filefmt-1.2 {
           34  +  hexio_write test.db 0 54
           35  +  set x [catch {sqlite3 db test.db} err]
           36  +  lappend x $err
           37  +} {0 {}}
           38  +do_test filefmt-1.3 {
           39  +  catchsql {
           40  +    SELECT count(*) FROM sqlite_master
           41  +  }
           42  +} {1 {file is encrypted or is not a database}}
           43  +do_test filefmt-1.4 {
           44  +  db close
           45  +  hexio_write test.db 0 53
           46  +  sqlite3 db test.db
           47  +  catchsql {
           48  +    SELECT count(*) FROM sqlite_master
           49  +  }
           50  +} {0 1}
           51  +
           52  +# The page-size is stored at offset 16
           53  +#
           54  +ifcapable pager_pragmas {
           55  +  foreach pagesize {512 1024 2048 4096 8192 16384 32768} {
           56  +     do_test filefmt-1.5.$pagesize.1 {
           57  +       db close
           58  +       file delete -force test.db
           59  +       sqlite3 db test.db
           60  +       db eval "PRAGMA page_size=$pagesize"
           61  +       db eval {CREATE TABLE t1(x)}
           62  +       file size test.db
           63  +     } [expr $pagesize*2]
           64  +     do_test filefmt-1.5.$pagesize.2 {
           65  +       hexio_get_int [hexio_read test.db 16 2]
           66  +     } $pagesize
           67  +  }
           68  +}
           69  +
           70  +# The page-size must be a power of 2
           71  +#
           72  +do_test filefmt-1.6 {
           73  +  db close
           74  +  hexio_write test.db 16 [hexio_render_int16 1025]
           75  +  sqlite3 db test.db
           76  +  catchsql {
           77  +     SELECT count(*) FROM sqlite_master
           78  +  }
           79  +} {1 {file is encrypted or is not a database}}
           80  +
           81  +
           82  +# The page-size must be at least 512 bytes
           83  +#
           84  +do_test filefmt-1.7 {
           85  +  db close
           86  +  hexio_write test.db 16 [hexio_render_int16 256]
           87  +  sqlite3 db test.db
           88  +  catchsql {
           89  +     SELECT count(*) FROM sqlite_master
           90  +  }
           91  +} {1 {file is encrypted or is not a database}}
           92  +
           93  +# Usable space per page (page-size minus unused space per page)
           94  +# must be at least 500 bytes
           95  +#
           96  +ifcapable pager_pragmas {
           97  +  do_test filefmt-1.8 {
           98  +    db close
           99  +    file delete -force test.db
          100  +    sqlite3 db test.db
          101  +    db eval {PRAGMA page_size=512; CREATE TABLE t1(x)}
          102  +    db close
          103  +    hexio_write test.db 20 10
          104  +    sqlite3 db test.db
          105  +    catchsql {
          106  +       SELECT count(*) FROM sqlite_master
          107  +    }
          108  +  } {1 {file is encrypted or is not a database}}
          109  +}
          110  +
          111  +
          112  +finish_test

Changes to test/select1.test.

     7      7   #    May you find forgiveness for yourself and forgive others.
     8      8   #    May you share freely, never taking more than you give.
     9      9   #
    10     10   #***********************************************************************
    11     11   # This file implements regression tests for SQLite library.  The
    12     12   # focus of this file is testing the SELECT statement.
    13     13   #
    14         -# $Id: select1.test,v 1.51 2006/04/11 14:16:22 drh Exp $
           14  +# $Id: select1.test,v 1.52 2007/04/06 15:02:14 drh Exp $
    15     15   
    16     16   set testdir [file dirname $argv0]
    17     17   source $testdir/tester.tcl
    18     18   
    19     19   # Try to select on a non-existant table.
    20     20   #
    21     21   do_test select1-1.1 {
................................................................................
   542    542   } {1 {near ")": syntax error}}
   543    543   do_test select1-7.8 {
   544    544     set v [catch {execsql {
   545    545        SELECT f1 FROM test1 ORDER BY f2, f1+;
   546    546     }} msg]
   547    547     lappend v $msg
   548    548   } {1 {near ";": syntax error}}
          549  +do_test select1-7.9 {
          550  +  catchsql {
          551  +     SELECT f1 FROM test1 LIMIT 5+3 OFFSET 11 ORDER BY f2;
          552  +  }
          553  +} {1 {near "ORDER": syntax error}}
   549    554   
   550    555   do_test select1-8.1 {
   551    556     execsql {SELECT f1 FROM test1 WHERE 4.3+2.4 OR 1 ORDER BY f1}
   552    557   } {11 33}
   553    558   do_test select1-8.2 {
   554    559     execsql {
   555    560       SELECT f1 FROM test1 WHERE ('x' || f1) BETWEEN 'x10' AND 'x20'