SQLite

Check-in [c287a7b294]
Login

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

Overview
Comment:Avoid an out-of-bounds read in sqlite3_prepare() and fix a case where the output variable *pzTail was being set incorrectly. Fix for #3027. (CVS 4957)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c287a7b29410be12cf88f886e8e2525a42aa9c03
User & Date: danielk1977 2008-04-03 14:36:26.000
Context
2008-04-03
16:01
Add the speedtest8.c and speedtest16.c files to the tools subdirectory. (CVS 4958) (check-in: b8d211a76f user: drh tags: trunk)
14:36
Avoid an out-of-bounds read in sqlite3_prepare() and fix a case where the output variable *pzTail was being set incorrectly. Fix for #3027. (CVS 4957) (check-in: c287a7b294 user: danielk1977 tags: trunk)
10:13
Change the allocator in mem2.c (used when SQLITE_MEMDEBUG is defined) so that allocations are not rounded up to the nearest 4 byte boundary. Fix a couple of errors in malloc.test related to sqlite3OsAccess() returning -1. (CVS 4956) (check-in: fd97f8762c user: danielk1977 tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/prepare.c.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains the implementation of the sqlite3_prepare()
** interface, and routines that contribute to loading the database schema
** from disk.
**
** $Id: prepare.c,v 1.82 2008/03/25 09:47:35 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** Fill the InitData structure with an error message that indicates
** that the database is corrupt.







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains the implementation of the sqlite3_prepare()
** interface, and routines that contribute to loading the database schema
** from disk.
**
** $Id: prepare.c,v 1.83 2008/04/03 14:36:26 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** Fill the InitData structure with an error message that indicates
** that the database is corrupt.
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566

567
568

569
570
571
572
573
574
575
        return SQLITE_LOCKED;
      }
    }
  }
  
  memset(&sParse, 0, sizeof(sParse));
  sParse.db = db;
  if( nBytes>=0 && zSql[nBytes]!=0 ){
    char *zSqlCopy;
    int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
    if( nBytes>mxLen ){
      sqlite3Error(db, SQLITE_TOOBIG, "statement too long");
      (void)sqlite3SafetyOff(db);
      return SQLITE_TOOBIG;
    }
    zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes);
    if( zSqlCopy ){
      sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg);
      sqlite3_free(zSqlCopy);

    }
    sParse.zTail = &zSql[nBytes];

  }else{
    sqlite3RunParser(&sParse, zSql, &zErrMsg);
  }

  if( db->mallocFailed ){
    sParse.rc = SQLITE_NOMEM;
  }







|











>
|
|
>







548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
        return SQLITE_LOCKED;
      }
    }
  }
  
  memset(&sParse, 0, sizeof(sParse));
  sParse.db = db;
  if( nBytes>=0 && zSql[nBytes-1]!=0 ){
    char *zSqlCopy;
    int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
    if( nBytes>mxLen ){
      sqlite3Error(db, SQLITE_TOOBIG, "statement too long");
      (void)sqlite3SafetyOff(db);
      return SQLITE_TOOBIG;
    }
    zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes);
    if( zSqlCopy ){
      sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg);
      sqlite3_free(zSqlCopy);
      sParse.zTail = &zSql[sParse.zTail-zSqlCopy];
    }else{
      sParse.zTail = &zSql[nBytes];
    }
  }else{
    sqlite3RunParser(&sParse, zSql, &zErrMsg);
  }

  if( db->mallocFailed ){
    sParse.rc = SQLITE_NOMEM;
  }
Changes to src/sqlite.h.in.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
** on how SQLite interfaces are suppose to operate.
**
** The name of this file under configuration management is "sqlite.h.in".
** The makefile makes some minor changes to this file (such as inserting
** the version number) and changes its name to "sqlite3.h" as
** part of the build process.
**
** @(#) $Id: sqlite.h.in,v 1.301 2008/03/26 18:34:43 danielk1977 Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** Make sure we can call this stuff from C++.







|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
** on how SQLite interfaces are suppose to operate.
**
** The name of this file under configuration management is "sqlite.h.in".
** The makefile makes some minor changes to this file (such as inserting
** the version number) and changes its name to "sqlite3.h" as
** part of the build process.
**
** @(#) $Id: sqlite.h.in,v 1.302 2008/04/03 14:36:26 danielk1977 Exp $
*/
#ifndef _SQLITE3_H_
#define _SQLITE3_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** Make sure we can call this stuff from C++.
2288
2289
2290
2291
2292
2293
2294
2295




2296
2297
2298
2299
2300
2301
2302
** use UTF-16. {END}
**
** If the nByte argument is less
** than zero, then zSql is read up to the first zero terminator.
** If nByte is non-negative, then it is the maximum number of 
** bytes read from zSql.  When nByte is non-negative, the
** zSql string ends at either the first '\000' or '\u0000' character or 
** until the nByte-th byte, whichever comes first. {END}




**
** *pzTail is made to point to the first byte past the end of the
** first SQL statement in zSql.  These routines only compiles the first
** statement in zSql, so *pzTail is left pointing to what remains
** uncompiled.
**
** *ppStmt is left pointing to a compiled [prepared statement] that can be







|
>
>
>
>







2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
** use UTF-16. {END}
**
** If the nByte argument is less
** than zero, then zSql is read up to the first zero terminator.
** If nByte is non-negative, then it is the maximum number of 
** bytes read from zSql.  When nByte is non-negative, the
** zSql string ends at either the first '\000' or '\u0000' character or 
** until the nByte-th byte, whichever comes first. If the caller knows
** that the supplied string is nul-terminated, then there is a small
** performance advantage to be had by passing an nByte parameter that 
** is equal to the number of bytes in the input string <i>including</i> 
** the nul-terminator bytes.{END}
**
** *pzTail is made to point to the first byte past the end of the
** first SQL statement in zSql.  These routines only compiles the first
** statement in zSql, so *pzTail is left pointing to what remains
** uncompiled.
**
** *ppStmt is left pointing to a compiled [prepared statement] that can be
Changes to src/test1.c.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.295 2008/03/22 01:07:18 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>

/*







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.296 2008/04/03 14:36:26 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>

/*
3047
3048
3049
3050
3051
3052
3053



3054
3055
3056
3057
3058
3059
3060
  if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;

  rc = sqlite3_prepare(db, zSql, bytes, &pStmt, &zTail);
  if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
  if( zTail ){
    if( bytes>=0 ){
      bytes = bytes - (zTail-zSql);



    }
    Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
  }
  if( rc!=SQLITE_OK ){
    assert( pStmt==0 );
    sprintf(zBuf, "(%d) ", rc);
    Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);







>
>
>







3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
  if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;

  rc = sqlite3_prepare(db, zSql, bytes, &pStmt, &zTail);
  if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
  if( zTail ){
    if( bytes>=0 ){
      bytes = bytes - (zTail-zSql);
    }
    if( strlen(zTail)<bytes ){
      bytes = strlen(zTail);
    }
    Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
  }
  if( rc!=SQLITE_OK ){
    assert( pStmt==0 );
    sprintf(zBuf, "(%d) ", rc);
    Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
Changes to test/capi3.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2003 January 29
#
# 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.  The
# focus of this script testing the callback-free C/C++ API.
#
# $Id: capi3.test,v 1.61 2008/03/19 13:03:34 drh Exp $
#

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

# Return the UTF-16 representation of the supplied UTF-8 string $str.
# If $nt is true, append two 0x00 bytes as a nul terminator.













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2003 January 29
#
# 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.  The
# focus of this script testing the callback-free C/C++ API.
#
# $Id: capi3.test,v 1.62 2008/04/03 14:36:26 danielk1977 Exp $
#

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

# Return the UTF-16 representation of the supplied UTF-8 string $str.
# If $nt is true, append two 0x00 bytes as a nul terminator.
70
71
72
73
74
75
76













77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
do_test capi3-1.4 {
  set sql {SELECT name FROM sqlite_master;SELECT 10}
  set STMT [sqlite3_prepare $DB $sql -1 TAIL]
  sqlite3_finalize $STMT
  set TAIL
} {SELECT 10}
do_test capi3-1.5 {













  set sql {SELECT namex FROM sqlite_master}
  catch {
    set STMT [sqlite3_prepare $DB $sql -1 TAIL]
  }
} {1}
do_test capi3-1.6 {
  sqlite3_errcode $DB
} {SQLITE_ERROR}
do_test capi3-1.7 {
  sqlite3_errmsg $DB
} {no such column: namex}

ifcapable {utf16} {
  do_test capi3-2.1 {
    set sql16 [utf16 {SELECT name FROM sqlite_master}]
    set STMT [sqlite3_prepare16 $DB $sql16 -1 ::TAIL]







>
>
>
>
>
>
>
>
>
>
>
>
>





|


|







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
do_test capi3-1.4 {
  set sql {SELECT name FROM sqlite_master;SELECT 10}
  set STMT [sqlite3_prepare $DB $sql -1 TAIL]
  sqlite3_finalize $STMT
  set TAIL
} {SELECT 10}
do_test capi3-1.5 {
  set sql {SELECT name FROM sqlite_master;SELECT 10}
  set STMT [sqlite3_prepare $DB $sql [string length $sql] TAIL]
  sqlite3_finalize $STMT
  set TAIL
} {SELECT 10}
do_test capi3-1.6 {
  set sql {SELECT name FROM sqlite_master;SELECT 10}
  set STMT [sqlite3_prepare $DB $sql [expr [string length $sql]+1] TAIL]
  sqlite3_finalize $STMT
  set TAIL
} {SELECT 10}

do_test capi3-1.7 {
  set sql {SELECT namex FROM sqlite_master}
  catch {
    set STMT [sqlite3_prepare $DB $sql -1 TAIL]
  }
} {1}
do_test capi3-1.8 {
  sqlite3_errcode $DB
} {SQLITE_ERROR}
do_test capi3-1.9 {
  sqlite3_errmsg $DB
} {no such column: namex}

ifcapable {utf16} {
  do_test capi3-2.1 {
    set sql16 [utf16 {SELECT name FROM sqlite_master}]
    set STMT [sqlite3_prepare16 $DB $sql16 -1 ::TAIL]
Added test/crash7.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
# 2008 March 20
#
# 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.
#
#***********************************************************************
#
# $Id: crash7.test,v 1.1 2008/04/03 14:36:26 danielk1977 Exp $

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

ifcapable !crashtest {
  finish_test
  return
}

proc signature {} {
  return [db eval {SELECT count(*), md5sum(a), md5sum(b), md5sum(c) FROM abc}]
}

foreach f [list test.db test.db-journal] {
  for {set ii 1} {$ii < 64} {incr ii} {
    db close
    file delete test.db
    sqlite3 db test.db
  
    set from_size [expr 1024 << ($ii&3)]
    set to_size   [expr 1024 << (($ii>>2)&3)]
  
    execsql "
      PRAGMA page_size = $from_size;
      BEGIN;
      CREATE TABLE abc(a PRIMARY KEY, b, c);
      INSERT INTO abc VALUES(randomblob(100), randomblob(200), randomblob(1000));
      INSERT INTO abc 
          SELECT randomblob(1000), randomblob(200), randomblob(100)
          FROM abc;
      INSERT INTO abc 
          SELECT randomblob(100), randomblob(200), randomblob(1000)
          FROM abc;
      INSERT INTO abc 
          SELECT randomblob(100), randomblob(200), randomblob(1000)
          FROM abc;
      INSERT INTO abc 
          SELECT randomblob(100), randomblob(200), randomblob(1000)
          FROM abc;
      INSERT INTO abc 
          SELECT randomblob(100), randomblob(200), randomblob(1000)
          FROM abc WHERE [expr $ii&16];
      INSERT INTO abc 
          SELECT randomblob(25), randomblob(45), randomblob(9456)
          FROM abc WHERE [expr $ii&32];
      INSERT INTO abc 
          SELECT randomblob(100), randomblob(200), randomblob(1000)
          FROM abc WHERE [expr $ii&8];
      INSERT INTO abc 
          SELECT randomblob(25), randomblob(45), randomblob(9456)
          FROM abc WHERE [expr $ii&4];
      COMMIT;
    "
  
    set sig [signature]
    db close
  
    do_test crash7-1.$ii.crash {
       crashsql -file $f "
         PRAGMA page_size = $to_size;
         VACUUM;
       "
    } {1 {child process exited abnormally}}
  
    sqlite3 db test.db
    integrity_check crash7-1.$ii.integrity
  } 
}

finish_test
Added test/vacuum3.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
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
# 2007 March 19
#
# 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.  The
# focus of this file is changing the database page size using a 
# VACUUM statement.
#
# $Id: vacuum3.test,v 1.1 2008/04/03 14:36:26 danielk1977 Exp $

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

# If the VACUUM statement is disabled in the current build, skip all
# the tests in this file.
#
ifcapable !vacuum {
  finish_test
  return
}


#-------------------------------------------------------------------
# Test cases vacuum3-1.* convert a simple 2-page database between a 
# few different page sizes.
#
do_test vacuum3-1.1 {
  execsql {
    PRAGMA page_size = 1024;
    CREATE TABLE t1(a, b, c);
    INSERT INTO t1 VALUES(1, 2, 3);
  }
} {}
do_test vacuum3-1.2 {
  execsql { PRAGMA page_size }
} {1024}
do_test vacuum3-1.3 {
  file size test.db
} {2048}

set I 4
foreach {request actual database} [list \
  2048 2048 4096                        \
  1024 1024 2048                        \
  1170 1024 2048                        \
  256  1024 2048                        \
  512  512  1024                        \
  4096 4096 8192                        \
  1024 1024 2048                        \
] {
if {$I==10} breakpoint
  do_test vacuum3-1.$I.1 {
    execsql " 
      PRAGMA page_size = $request;
      VACUUM;
    "
    execsql { PRAGMA page_size }
  } $actual
  do_test vacuum3-1.$I.2 {
    file size test.db
  } $database
  do_test vacuum3-1.$I.3 {
    execsql { SELECT * FROM t1 }
  } {1 2 3}
  integrity_check vacuum3-1.$I.4

  incr I
}

#-------------------------------------------------------------------
# Test cases vacuum3-2.* convert a simple 3-page database between a 
# few different page sizes.
#
do_test vacuum3-2.1 {
  execsql {
    PRAGMA page_size = 1024;
    VACUUM;
    ALTER TABLE t1 ADD COLUMN d;
    UPDATE t1 SET d = randomblob(1000);
  }
  file size test.db
} {3072}
do_test vacuum3-2.2 {
  execsql { PRAGMA page_size }
} {1024}
do_test vacuum3-2.3 {
  set blob [db one {select d from t1}]
  string length $blob
} {1000}

set I 4
foreach {request actual database} [list \
  2048 2048 4096                        \
  1024 1024 3072                        \
  1170 1024 3072                        \
  256  1024 3072                        \
  512  512  2048                        \
  4096 4096 8192                        \
  1024 1024 3072                        \
] {
if {$I==10} breakpoint
  do_test vacuum3-2.$I.1 {
    execsql " 
      PRAGMA page_size = $request;
      VACUUM;
    "
    execsql { PRAGMA page_size }
  } $actual
  do_test vacuum3-2.$I.2 {
    file size test.db
  } $database
  do_test vacuum3-2.$I.3 {
    execsql { SELECT * FROM t1 }
  } [list 1 2 3 $blob]
  integrity_check vacuum3-1.$I.4

  incr I
}

#-------------------------------------------------------------------
# Test cases vacuum3-3.* converts a database large enough to include
# the locking page (in a test environment) between few different 
# page sizes.
#
proc signature {} {
  return [db eval {SELECT count(*), md5sum(a), md5sum(b), md5sum(c) FROM abc}]
}
do_test vacuum3-3.1 {
  execsql "
    PRAGMA page_size = 1024;
    BEGIN;
    CREATE TABLE abc(a PRIMARY KEY, b, c);
    INSERT INTO abc VALUES(randomblob(100), randomblob(200), randomblob(1000));
    INSERT INTO abc 
        SELECT randomblob(1000), randomblob(200), randomblob(100)
        FROM abc;
    INSERT INTO abc 
        SELECT randomblob(100), randomblob(200), randomblob(1000)
        FROM abc;
    INSERT INTO abc 
        SELECT randomblob(100), randomblob(200), randomblob(1000)
        FROM abc;
    INSERT INTO abc 
        SELECT randomblob(100), randomblob(200), randomblob(1000)
        FROM abc;
    INSERT INTO abc 
        SELECT randomblob(100), randomblob(200), randomblob(1000)
        FROM abc;
    INSERT INTO abc 
        SELECT randomblob(25), randomblob(45), randomblob(9456)
        FROM abc;
    INSERT INTO abc 
        SELECT randomblob(100), randomblob(200), randomblob(1000)
        FROM abc;
    INSERT INTO abc 
        SELECT randomblob(25), randomblob(45), randomblob(9456)
        FROM abc;
    COMMIT;
  "
} {}
do_test vacuum3-3.2 {
  execsql { PRAGMA page_size }
} {1024}

set ::sig [signature]

set I 3
foreach {request actual} [list \
  2048 2048                    \
  1024 1024                    \
  1170 1024                    \
  256  1024                    \
  512  512                     \
  4096 4096                    \
  1024 1024                    \
] {
if {$I==10} breakpoint
  do_test vacuum3-3.$I.1 {
    execsql " 
      PRAGMA page_size = $request;
      VACUUM;
    "
    execsql { PRAGMA page_size }
  } $actual
  do_test vacuum3-3.$I.2 {
    signature
  } $::sig
  integrity_check vacuum3-3.$I.3

  incr I
}

do_ioerr_test vacuum3-ioerr-1 -cksum true -sqlprep { 
  PRAGMA page_size = 1024;
  BEGIN; 
  CREATE TABLE t1(a, b, c); 
  INSERT INTO t1 VALUES(1, randstr(50,50), randstr(50,50)); 
  INSERT INTO t1 SELECT a+2, b||'-'||rowid, c||'-'||rowid FROM t1; 
  INSERT INTO t1 SELECT a+4, b||'-'||rowid, c||'-'||rowid FROM t1;
  INSERT INTO t1 SELECT a+8, b||'-'||rowid, c||'-'||rowid FROM t1;
  INSERT INTO t1 SELECT a+16, b||'-'||rowid, c||'-'||rowid FROM t1;
  INSERT INTO t1 SELECT a+32, b||'-'||rowid, c||'-'||rowid FROM t1;
  INSERT INTO t1 SELECT a+64, b||'-'||rowid, c||'-'||rowid FROM t1;
  INSERT INTO t1 SELECT a+128, b||'-'||rowid, c||'-'||rowid FROM t1;
  INSERT INTO t1 VALUES(1, randstr(600,600), randstr(600,600));
  CREATE TABLE t2 AS SELECT * FROM t1;
  CREATE TABLE t3 AS SELECT * FROM t1;
  COMMIT;
  DROP TABLE t2;
} -sqlbody {
  PRAGMA page_size = 4096;
  VACUUM;
} 
do_ioerr_test vacuum3-ioerr-2 -cksum true -sqlprep { 
  PRAGMA page_size = 2048;
  BEGIN; 
  CREATE TABLE t1(a, b, c); 
  INSERT INTO t1 VALUES(1, randstr(50,50), randstr(50,50)); 
  INSERT INTO t1 SELECT a+2, b||'-'||rowid, c||'-'||rowid FROM t1; 
  INSERT INTO t1 SELECT a+4, b||'-'||rowid, c||'-'||rowid FROM t1;
  INSERT INTO t1 SELECT a+8, b||'-'||rowid, c||'-'||rowid FROM t1;
  INSERT INTO t1 SELECT a+16, b||'-'||rowid, c||'-'||rowid FROM t1;
  INSERT INTO t1 SELECT a+32, b||'-'||rowid, c||'-'||rowid FROM t1;
  INSERT INTO t1 SELECT a+64, b||'-'||rowid, c||'-'||rowid FROM t1;
  INSERT INTO t1 SELECT a+128, b||'-'||rowid, c||'-'||rowid FROM t1;
  INSERT INTO t1 VALUES(1, randstr(600,600), randstr(600,600));
  CREATE TABLE t2 AS SELECT * FROM t1;
  CREATE TABLE t3 AS SELECT * FROM t1;
  COMMIT;
  DROP TABLE t2;
} -sqlbody {
  PRAGMA page_size = 512;
  VACUUM;
} 

source $testdir/malloc_common.tcl
if {$MEMDEBUG} {
  do_malloc_test vacuum3-malloc-1 -sqlprep { 
    PRAGMA page_size = 2048;
    BEGIN; 
    CREATE TABLE t1(a, b, c); 
    INSERT INTO t1 VALUES(1, randstr(50,50), randstr(50,50)); 
    INSERT INTO t1 SELECT a+2, b||'-'||rowid, c||'-'||rowid FROM t1; 
    INSERT INTO t1 SELECT a+4, b||'-'||rowid, c||'-'||rowid FROM t1;
    INSERT INTO t1 SELECT a+8, b||'-'||rowid, c||'-'||rowid FROM t1;
    INSERT INTO t1 SELECT a+16, b||'-'||rowid, c||'-'||rowid FROM t1;
    INSERT INTO t1 SELECT a+32, b||'-'||rowid, c||'-'||rowid FROM t1;
    INSERT INTO t1 SELECT a+64, b||'-'||rowid, c||'-'||rowid FROM t1;
    INSERT INTO t1 SELECT a+128, b||'-'||rowid, c||'-'||rowid FROM t1;
    INSERT INTO t1 VALUES(1, randstr(600,600), randstr(600,600));
    CREATE TABLE t2 AS SELECT * FROM t1;
    CREATE TABLE t3 AS SELECT * FROM t1;
    COMMIT;
    DROP TABLE t2;
  } -sqlbody {
    PRAGMA page_size = 512;
    VACUUM;
  } 
}

finish_test