/ Check-in [479b3d96]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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 Unified Diffs Ignore Whitespace Patch

Changes to Makefile.in.

218
219
220
221
222
223
224

225
226
227
228
229
230
231
  $(TOP)/src/test5.c \
  $(TOP)/src/test6.c \
  $(TOP)/src/test7.c \
  $(TOP)/src/test8.c \
  $(TOP)/src/test9.c \
  $(TOP)/src/test_autoext.c \
  $(TOP)/src/test_async.c \

  $(TOP)/src/test_md5.c \
  $(TOP)/src/test_schema.c \
  $(TOP)/src/test_server.c \
  $(TOP)/src/test_tclvar.c \
  $(TOP)/src/utf.c \
  $(TOP)/src/util.c \
  $(TOP)/src/vdbe.c \







>







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

Changes to main.mk.

173
174
175
176
177
178
179

180
181
182
183
184
185
186
  $(TOP)/src/test5.c \
  $(TOP)/src/test6.c \
  $(TOP)/src/test7.c \
  $(TOP)/src/test8.c \
  $(TOP)/src/test9.c \
  $(TOP)/src/test_autoext.c \
  $(TOP)/src/test_async.c \

  $(TOP)/src/test_md5.c \
  $(TOP)/src/test_schema.c \
  $(TOP)/src/test_server.c \
  $(TOP)/src/test_tclvar.c \
  $(TOP)/src/utf.c \
  $(TOP)/src/util.c \
  $(TOP)/src/vdbe.c \







>







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

Changes to src/btree.c.

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







|







 







|







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

Changes to src/parse.y.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
538
539
540
541
542
543
544








545
546
547
548

549
550
551
552
553
554
555
**
*************************************************************************
** This file contains SQLite's grammar for SQL.  Process this file
** using the lemon parser generator to generate C code that runs
** the parser.  Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.217 2007/04/06 11:26:00 drh Exp $
*/

// All token codes are small integers with #defines that begin with "TK_"
%token_prefix TK_

// The type of the data attached to each token is Token.  This is also the
// default type for non-terminals.
................................................................................

%type having_opt {Expr*}
%destructor having_opt {sqlite3ExprDelete($$);}
having_opt(A) ::= .                {A = 0;}
having_opt(A) ::= HAVING expr(X).  {A = X;}

%type limit_opt {struct LimitVal}








%destructor limit_opt {
  sqlite3ExprDelete($$.pLimit);
  sqlite3ExprDelete($$.pOffset);
}

limit_opt(A) ::= .                     {A.pLimit = 0; A.pOffset = 0;}
limit_opt(A) ::= LIMIT expr(X).        {A.pLimit = X; A.pOffset = 0;}
limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y). 
                                       {A.pLimit = X; A.pOffset = Y;}
limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y). 
                                       {A.pOffset = X; A.pLimit = Y;}








|







 







>
>
>
>
>
>
>
>
|
|
|
<
>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555

556
557
558
559
560
561
562
563
**
*************************************************************************
** This file contains SQLite's grammar for SQL.  Process this file
** using the lemon parser generator to generate C code that runs
** the parser.  Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.218 2007/04/06 15:02:14 drh Exp $
*/

// All token codes are small integers with #defines that begin with "TK_"
%token_prefix TK_

// The type of the data attached to each token is Token.  This is also the
// default type for non-terminals.
................................................................................

%type having_opt {Expr*}
%destructor having_opt {sqlite3ExprDelete($$);}
having_opt(A) ::= .                {A = 0;}
having_opt(A) ::= HAVING expr(X).  {A = X;}

%type limit_opt {struct LimitVal}

// The destructor for limit_opt will never fire in the current grammar.
// The limit_opt non-terminal only occurs at the end of a single production
// rule for SELECT statements.  As soon as the rule that create the 
// limit_opt non-terminal reduces, the SELECT statement rule will also
// reduce.  So there is never a limit_opt non-terminal on the stack 
// except as a transient.  So there is never anything to destroy.
//
//%destructor limit_opt {
//  sqlite3ExprDelete($$.pLimit);
//  sqlite3ExprDelete($$.pOffset);

//}
limit_opt(A) ::= .                     {A.pLimit = 0; A.pOffset = 0;}
limit_opt(A) ::= LIMIT expr(X).        {A.pLimit = X; A.pOffset = 0;}
limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y). 
                                       {A.pLimit = X; A.pOffset = Y;}
limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y). 
                                       {A.pOffset = X; A.pLimit = Y;}

Changes to src/tclsqlite.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
....
2214
2215
2216
2217
2218
2219
2220

2221
2222
2223
2224
2225
2226
2227
....
2228
2229
2230
2231
2232
2233
2234

2235
2236
2237
2238
2239
2240
2241
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** A TCL Interface to SQLite.  Append this file to sqlite3.c and
** compile the whole thing to build a TCL-enabled version of SQLite.
**
** $Id: tclsqlite.c,v 1.178 2007/04/05 21:58:33 drh Exp $
*/
#include "tcl.h"

/*
** Some additional include files are needed if this file is not
** appended to the amalgamation.
*/
................................................................................
    extern int Sqlitetest9_Init(Tcl_Interp*);
    extern int Md5_Init(Tcl_Interp*);
    extern int Sqlitetestsse_Init(Tcl_Interp*);
    extern int Sqlitetestasync_Init(Tcl_Interp*);
    extern int Sqlitetesttclvar_Init(Tcl_Interp*);
    extern int Sqlitetestschema_Init(Tcl_Interp*);
    extern int Sqlitetest_autoext_Init(Tcl_Interp*);


    Sqlitetest1_Init(interp);
    Sqlitetest2_Init(interp);
    Sqlitetest3_Init(interp);
    Sqlitetest4_Init(interp);
    Sqlitetest5_Init(interp);
    Sqlitetest6_Init(interp);
................................................................................
    Sqlitetest7_Init(interp);
    Sqlitetest8_Init(interp);
    Sqlitetest9_Init(interp);
    Sqlitetestasync_Init(interp);
    Sqlitetesttclvar_Init(interp);
    Sqlitetestschema_Init(interp);
    Sqlitetest_autoext_Init(interp);

    Md5_Init(interp);
#ifdef SQLITE_SSE
    Sqlitetestsse_Init(interp);
#endif
  }
#endif
  if( argc>=2 || TCLSH==2 ){







|







 







>







 







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
....
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
....
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** A TCL Interface to SQLite.  Append this file to sqlite3.c and
** compile the whole thing to build a TCL-enabled version of SQLite.
**
** $Id: tclsqlite.c,v 1.179 2007/04/06 15:02:14 drh Exp $
*/
#include "tcl.h"

/*
** Some additional include files are needed if this file is not
** appended to the amalgamation.
*/
................................................................................
    extern int Sqlitetest9_Init(Tcl_Interp*);
    extern int Md5_Init(Tcl_Interp*);
    extern int Sqlitetestsse_Init(Tcl_Interp*);
    extern int Sqlitetestasync_Init(Tcl_Interp*);
    extern int Sqlitetesttclvar_Init(Tcl_Interp*);
    extern int Sqlitetestschema_Init(Tcl_Interp*);
    extern int Sqlitetest_autoext_Init(Tcl_Interp*);
    extern int Sqlitetest_hexio_Init(Tcl_Interp*);

    Sqlitetest1_Init(interp);
    Sqlitetest2_Init(interp);
    Sqlitetest3_Init(interp);
    Sqlitetest4_Init(interp);
    Sqlitetest5_Init(interp);
    Sqlitetest6_Init(interp);
................................................................................
    Sqlitetest7_Init(interp);
    Sqlitetest8_Init(interp);
    Sqlitetest9_Init(interp);
    Sqlitetestasync_Init(interp);
    Sqlitetesttclvar_Init(interp);
    Sqlitetestschema_Init(interp);
    Sqlitetest_autoext_Init(interp);
    Sqlitetest_hexio_Init(interp);
    Md5_Init(interp);
#ifdef SQLITE_SSE
    Sqlitetestsse_Init(interp);
#endif
  }
#endif
  if( argc>=2 || TCLSH==2 ){

Added src/test_hexio.c.















































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
/*
** 2007 April 6
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces.  This code
** implements TCL commands for reading and writing the binary
** database files and displaying the content of those files as
** hexadecimal.  We could, in theory, use the built-in "binary"
** command of TCL to do a lot of this, but there are some issues
** with historical versions of the "binary" command.  So it seems
** easier and safer to build our own mechanism.
**
** $Id: test_hexio.c,v 1.1 2007/04/06 15:02:14 drh Exp $
*/
#include "tcl.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>

/*
hexio_read  filename offset amt
hexio_write filename offset hexdata
hexio_get_int  hexdata
hexio_get_varint  hexdata
hexio_render_int8  integer
hexio_render_int16  integer
hexio_render_int38  integer
hexio_render_varint  integer
*/

/*
** Convert binary to hex.  The input zBuf[] contains N bytes of
** binary data.  zBuf[] is 2*n+1 bytes long.  Overwrite zBuf[]
** with a hexadecimal representation of its original binary input.
*/
static void binToHex(unsigned char *zBuf, int N){
  const unsigned char zHex[] = "0123456789ABCDEF";
  int i, j;
  unsigned char c;
  i = N*2;
  zBuf[i--] = 0;
  for(j=N-1; j>=0; j--){
    c = zBuf[j];
    zBuf[i--] = zHex[c&0xf];
    zBuf[i--] = zHex[c>>4];
  }
  assert( i==-1 );
}

/*
** Convert hex to binary.  The input zIn[] contains N bytes of
** hexadecimal.  Convert this into binary and write aOut[] with
** the binary data.  Spaces in the original input are ignored.
** Return the number of bytes of binary rendered.
*/
static int hexToBin(const unsigned char *zIn, int N, unsigned char *aOut){
  const unsigned char aMap[] = {
     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
     1, 2, 3, 4, 5, 6, 7, 8,  9,10, 0, 0, 0, 0, 0, 0,
     0,11,12,13,14,15,16, 0,  0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
     0,11,12,13,14,15,16, 0,  0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  };
  int i, j;
  int hi=1;
  unsigned char c;

  for(i=j=0; i<N; i++){
    c = aMap[zIn[i]];
    if( c==0 ) continue;
    if( hi ){
      aOut[j] = (c-1)<<4;
      hi = 0;
    }else{
      aOut[j++] |= c-1;
      hi = 1;
    }
  }
  return j;
}


/*
** Usage:   hexio_read  FILENAME  OFFSET  AMT
**
** Read AMT bytes from file FILENAME beginning at OFFSET from the
** beginning of the file.  Convert that information to hexadecimal
** and return the resulting HEX string.
*/
static int hexio_read(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int offset;
  int amt, got;
  const char *zFile;
  unsigned char *zBuf;
  FILE *in;

  if( objc!=4 ){
    Tcl_WrongNumArgs(interp, 1, objv, "FILENAME OFFSET AMT");
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[2], &offset) ) return TCL_ERROR;
  if( Tcl_GetIntFromObj(interp, objv[3], &amt) ) return TCL_ERROR;
  zFile = Tcl_GetString(objv[1]);
  zBuf = malloc( amt*2+1 );
  if( zBuf==0 ){
    return TCL_ERROR;
  }
  in = fopen(zFile, "r");
  if( in==0 ){
    Tcl_AppendResult(interp, "cannot open input file ", zFile, 0);
    return TCL_ERROR;
  }
  fseek(in, offset, SEEK_SET);
  got = fread(zBuf, 1, amt, in);
  fclose(in);
  if( got<0 ){
    got = 0;
  }
  binToHex(zBuf, got);
  Tcl_AppendResult(interp, zBuf, 0);
  free(zBuf);
  return TCL_OK;
}


/*
** Usage:   hexio_write  FILENAME  OFFSET  DATA
**
** Write DATA into file FILENAME beginning at OFFSET from the
** beginning of the file.  DATA is expressed in hexadecimal.
*/
static int hexio_write(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int offset;
  int nIn, nOut, written;
  const char *zFile;
  const unsigned char *zIn;
  unsigned char *aOut;
  FILE *out;

  if( objc!=4 ){
    Tcl_WrongNumArgs(interp, 1, objv, "FILENAME OFFSET HEXDATA");
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[2], &offset) ) return TCL_ERROR;
  zFile = Tcl_GetString(objv[1]);
  zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[3], &nIn);
  aOut = malloc( nIn/2 );
  if( aOut==0 ){
    return TCL_ERROR;
  }
  nOut = hexToBin(zIn, nIn, aOut);
  out = fopen(zFile, "r+");
  if( out==0 ){
    Tcl_AppendResult(interp, "cannot open output file ", zFile, 0);
    return TCL_ERROR;
  }
  fseek(out, offset, SEEK_SET);
  written = fwrite(aOut, 1, nOut, out);
  free(aOut);
  fclose(out);
  Tcl_SetObjResult(interp, Tcl_NewIntObj(written));
  return TCL_OK;
}

/*
** USAGE:   hexio_get_int   HEXDATA
**
** Interpret the HEXDATA argument as a big-endian integer.  Return
** the value of that integer.  HEXDATA can contain between 2 and 8
** hexadecimal digits.
*/
static int hexio_get_int(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int val;
  int nIn, nOut;
  const unsigned char *zIn;
  unsigned char *aOut;
  unsigned char aNum[4];

  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "HEXDATA");
    return TCL_ERROR;
  }
  zIn = (const unsigned char *)Tcl_GetStringFromObj(objv[1], &nIn);
  aOut = malloc( nIn/2 );
  if( aOut==0 ){
    return TCL_ERROR;
  }
  nOut = hexToBin(zIn, nIn, aOut);
  if( nOut>=4 ){
    memcpy(aNum, aOut, 4);
  }else{
    memset(aNum, 0, sizeof(aNum));
    memcpy(&aNum[4-nOut], aOut, 4-nOut);
  }
  free(aOut);
  val = (aNum[0]<<24) | (aNum[1]<<16) | (aNum[2]<<8) | aNum[3];
  Tcl_SetObjResult(interp, Tcl_NewIntObj(val));
  return TCL_OK;
}


/*
** USAGE:   hexio_render_int16   INTEGER
**
** Render INTEGER has a 16-bit big-endian integer in hexadecimal.
*/
static int hexio_render_int16(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int val;
  unsigned char aNum[10];

  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "INTEGER");
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[1], &val) ) return TCL_ERROR;
  aNum[0] = val>>8;
  aNum[1] = val;
  binToHex(aNum, 2);
  Tcl_SetObjResult(interp, Tcl_NewStringObj((char*)aNum, 4));
  return TCL_OK;
}


/*
** USAGE:   hexio_render_int32   INTEGER
**
** Render INTEGER has a 32-bit big-endian integer in hexadecimal.
*/
static int hexio_render_int32(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int val;
  unsigned char aNum[10];

  if( objc!=2 ){
    Tcl_WrongNumArgs(interp, 1, objv, "INTEGER");
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[1], &val) ) return TCL_ERROR;
  aNum[0] = val>>24;
  aNum[1] = val>>16;
  aNum[2] = val>>8;
  aNum[3] = val;
  binToHex(aNum, 4);
  Tcl_SetObjResult(interp, Tcl_NewStringObj((char*)aNum, 8));
  return TCL_OK;
}



/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest_hexio_Init(Tcl_Interp *interp){
  static struct {
     char *zName;
     Tcl_ObjCmdProc *xProc;
  } aObjCmd[] = {
     { "hexio_read",                   hexio_read            },
     { "hexio_write",                  hexio_write           },
     { "hexio_get_int",                hexio_get_int         },
     { "hexio_render_int16",           hexio_render_int16    },
     { "hexio_render_int32",           hexio_render_int32    },
  };
  int i;
  for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
    Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
  }
  return TCL_OK;
}

Added test/corrupt3.test.

























































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# 2007 April 6
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests to make sure SQLite does not crash or
# segfault if it sees a corrupt database file.
#
# $Id: corrupt3.test,v 1.1 2007/04/06 15:02:14 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# We must have the page_size pragma for these tests to work.
#
ifcapable !pager_pragmas {
  finish_test
  return
}

# Create a database with an overflow page.
#
do_test corrupt3-1.1 {
  set bigstring [string repeat 0123456789 200]
  execsql {
    PRAGMA page_size=1024;
    CREATE TABLE t1(x);
    INSERT INTO t1 VALUES($bigstring);
  }
  file size test.db
} [expr {1024*3}]

# Verify that the file format is as we expect.  The page size
# should be 1024 bytes.  The only record should have a single
# overflow page.  The overflow page is page 3.  The pointer to
# the overflow page is on the last 4 bytes of page 2.
#
do_test corrupt3-1.2 {
  hexio_get_int [hexio_read test.db 16 2]
} 1024   ;# The page size is 1024
do_test corrupt3-1.3 {
  hexio_get_int [hexio_read test.db 20 1]
} 0      ;# Unused bytes per page is 0
do_test corrupt3-1.4 {
  hexio_get_int [hexio_read test.db 2044 4]
} 3      ;# Overflow page is 3
do_test corrupt3-1.5 {
  hexio_get_int [hexio_read test.db 2048 4]
} 0      ;# First chained overflow is 0

integrity_check corrupt3-1.6

# Make the overflow chain loop back on itself.   See if the
# corruption is detected.   (Actually, the last pointer in
# an overflow chain is ignored, so this is not an error.)
#
do_test corrupt3-1.7 {
  db close
  hexio_write test.db 2048 [hexio_render_int32 3]
  sqlite3 db test.db
  catchsql {
    SELECT x FROM t1
  }
} [list 0 $bigstring]
integrity_check corrupt3-1.8

# Change the pointer for the first page of the overflow
# change to be a non-existant page.
#
do_test corrupt3-1.9 {
  db close
  hexio_write test.db 2044 [hexio_render_int32 4]
  sqlite3 db test.db
  catchsql {
    SELECT substr(x,1,10) FROM t1
  }
} [list 0 0123456789]
do_test corrupt3-1.10 {
  catchsql {
    PRAGMA integrity_check
  }
} {0 {{*** in database main ***
On tree page 2 cell 0: invalid page number 4
Page 3 is never used}}}
do_test corrupt3-1.11 {
  db close
  hexio_write test.db 2044 [hexio_render_int32 0]
  sqlite3 db test.db
  catchsql {
    SELECT substr(x,1,10) FROM t1
  }
} [list 1 {database disk image is malformed}]
do_test corrupt3-1.12 {
  catchsql {
    PRAGMA integrity_check
  }
} {0 {{*** in database main ***
On tree page 2 cell 0: 1 of 1 pages missing from overflow list starting at 0
Page 3 is never used}}}

finish_test

Added test/filefmt.test.

































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# 2007 April 6
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests to verify database file format.
#
# $Id: filefmt.test,v 1.1 2007/04/06 15:02:14 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl
db close
file delete -force test.db test.db-journal

# Database begins with valid 16-byte header string.
#
do_test filefmt-1.1 {
  sqlite3 db test.db
  db eval {CREATE TABLE t1(x)}
  db close
  hexio_read test.db 0 16
} {53514C69746520666F726D6174203300}

# If the 16-byte header is changed, the file will not open
#
do_test filefmt-1.2 {
  hexio_write test.db 0 54
  set x [catch {sqlite3 db test.db} err]
  lappend x $err
} {0 {}}
do_test filefmt-1.3 {
  catchsql {
    SELECT count(*) FROM sqlite_master
  }
} {1 {file is encrypted or is not a database}}
do_test filefmt-1.4 {
  db close
  hexio_write test.db 0 53
  sqlite3 db test.db
  catchsql {
    SELECT count(*) FROM sqlite_master
  }
} {0 1}

# The page-size is stored at offset 16
#
ifcapable pager_pragmas {
  foreach pagesize {512 1024 2048 4096 8192 16384 32768} {
     do_test filefmt-1.5.$pagesize.1 {
       db close
       file delete -force test.db
       sqlite3 db test.db
       db eval "PRAGMA page_size=$pagesize"
       db eval {CREATE TABLE t1(x)}
       file size test.db
     } [expr $pagesize*2]
     do_test filefmt-1.5.$pagesize.2 {
       hexio_get_int [hexio_read test.db 16 2]
     } $pagesize
  }
}

# The page-size must be a power of 2
#
do_test filefmt-1.6 {
  db close
  hexio_write test.db 16 [hexio_render_int16 1025]
  sqlite3 db test.db
  catchsql {
     SELECT count(*) FROM sqlite_master
  }
} {1 {file is encrypted or is not a database}}


# The page-size must be at least 512 bytes
#
do_test filefmt-1.7 {
  db close
  hexio_write test.db 16 [hexio_render_int16 256]
  sqlite3 db test.db
  catchsql {
     SELECT count(*) FROM sqlite_master
  }
} {1 {file is encrypted or is not a database}}

# Usable space per page (page-size minus unused space per page)
# must be at least 500 bytes
#
ifcapable pager_pragmas {
  do_test filefmt-1.8 {
    db close
    file delete -force test.db
    sqlite3 db test.db
    db eval {PRAGMA page_size=512; CREATE TABLE t1(x)}
    db close
    hexio_write test.db 20 10
    sqlite3 db test.db
    catchsql {
       SELECT count(*) FROM sqlite_master
    }
  } {1 {file is encrypted or is not a database}}
}


finish_test

Changes to test/select1.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
542
543
544
545
546
547
548





549
550
551
552
553
554
555
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the SELECT statement.
#
# $Id: select1.test,v 1.51 2006/04/11 14:16:22 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Try to select on a non-existant table.
#
do_test select1-1.1 {
................................................................................
} {1 {near ")": syntax error}}
do_test select1-7.8 {
  set v [catch {execsql {
     SELECT f1 FROM test1 ORDER BY f2, f1+;
  }} msg]
  lappend v $msg
} {1 {near ";": syntax error}}






do_test select1-8.1 {
  execsql {SELECT f1 FROM test1 WHERE 4.3+2.4 OR 1 ORDER BY f1}
} {11 33}
do_test select1-8.2 {
  execsql {
    SELECT f1 FROM test1 WHERE ('x' || f1) BETWEEN 'x10' AND 'x20'







|







 







>
>
>
>
>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the SELECT statement.
#
# $Id: select1.test,v 1.52 2007/04/06 15:02:14 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Try to select on a non-existant table.
#
do_test select1-1.1 {
................................................................................
} {1 {near ")": syntax error}}
do_test select1-7.8 {
  set v [catch {execsql {
     SELECT f1 FROM test1 ORDER BY f2, f1+;
  }} msg]
  lappend v $msg
} {1 {near ";": syntax error}}
do_test select1-7.9 {
  catchsql {
     SELECT f1 FROM test1 LIMIT 5+3 OFFSET 11 ORDER BY f2;
  }
} {1 {near "ORDER": syntax error}}

do_test select1-8.1 {
  execsql {SELECT f1 FROM test1 WHERE 4.3+2.4 OR 1 ORDER BY f1}
} {11 33}
do_test select1-8.2 {
  execsql {
    SELECT f1 FROM test1 WHERE ('x' || f1) BETWEEN 'x10' AND 'x20'