/ Check-in [63894baf]
Login

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

Overview
Comment:Fix a problem with VACUUM that can lead to database corruption. (CVS 2323)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:63894baf1b37156fd0b84eba4c9c5e8f43cee3f3
User & Date: drh 2005-02-12 00:19:30
Context
2005-02-12
08:59
Fix a problem with sub-queries and the flattening optimization. Also handle an extra case of database corruption. (CVS 2324) check-in: f7858d88 user: danielk1977 tags: trunk
00:19
Fix a problem with VACUUM that can lead to database corruption. (CVS 2323) check-in: 63894baf user: drh tags: trunk
2005-02-09
07:05
Return SQLITE_BUSY if the database is locked reading the schema within sqlite_prepare(). Ticket #1106. (CVS 2322) check-in: c33c02d6 user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/vacuum.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
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
**
*************************************************************************
** This file contains code used to implement the VACUUM command.
**
** Most of the code in this file may be omitted by defining the
** SQLITE_OMIT_VACUUM macro.
**
** $Id: vacuum.c,v 1.38 2005/02/05 12:48:48 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"

#ifndef SQLITE_OMIT_VACUUM
/*
** Generate a random name of 20 character in length.
................................................................................
  ** call to sqlite3BtreeCopyFile(). The main database btree level
  ** transaction is then committed, so the SQL level never knows it was
  ** opened for writing. This way, the SQL transaction used to create the
  ** temporary database never needs to be committed.
  */
  if( sqlite3BtreeIsInTrans(pTemp) ){
    u32 meta;















    assert( 0==sqlite3BtreeIsInTrans(pMain) );
    rc = sqlite3BtreeBeginTrans(pMain, 1);
    if( rc!=SQLITE_OK ) goto end_of_vacuum;

    /* Copy Btree meta values 3 and 4. These correspond to SQL layer meta 
    ** values 2 and 3, the default values of a couple of pragmas.
    */
    rc = sqlite3BtreeGetMeta(pMain, 3, &meta);
    if( rc!=SQLITE_OK ) goto end_of_vacuum;
    rc = sqlite3BtreeUpdateMeta(pTemp, 3, meta);
    if( rc!=SQLITE_OK ) goto end_of_vacuum;
    rc = sqlite3BtreeGetMeta(pMain, 4, &meta);
    if( rc!=SQLITE_OK ) goto end_of_vacuum;
    rc = sqlite3BtreeUpdateMeta(pTemp, 4, meta);
    if( rc!=SQLITE_OK ) goto end_of_vacuum;


    rc = sqlite3BtreeCopyFile(pMain, pTemp);
    if( rc!=SQLITE_OK ) goto end_of_vacuum;
    rc = sqlite3BtreeCommit(pMain);
  }

end_of_vacuum:







|







 







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





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







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
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
**
*************************************************************************
** This file contains code used to implement the VACUUM command.
**
** Most of the code in this file may be omitted by defining the
** SQLITE_OMIT_VACUUM macro.
**
** $Id: vacuum.c,v 1.39 2005/02/12 00:19:30 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"

#ifndef SQLITE_OMIT_VACUUM
/*
** Generate a random name of 20 character in length.
................................................................................
  ** call to sqlite3BtreeCopyFile(). The main database btree level
  ** transaction is then committed, so the SQL level never knows it was
  ** opened for writing. This way, the SQL transaction used to create the
  ** temporary database never needs to be committed.
  */
  if( sqlite3BtreeIsInTrans(pTemp) ){
    u32 meta;
    int i;

    /* This array determines which meta meta values are preserved in the
    ** vacuum.  Even entries are the meta value number and odd entries
    ** are an increment to apply to the meta value after the vacuum.
    ** The increment is used to increase the schema cookie so that other
    ** connections to the same database will know to reread the schema.
    */
    static const unsigned char aCopy[] = {
       1, 1,    /* Add one to the old schema cookie */
       3, 0,    /* Preserve the default page cache size */
       5, 0,    /* Preserve the default text encoding */
       6, 0,    /* Preserve the user version */
    };

    assert( 0==sqlite3BtreeIsInTrans(pMain) );
    rc = sqlite3BtreeBeginTrans(pMain, 1);
    if( rc!=SQLITE_OK ) goto end_of_vacuum;

    /* Copy Btree meta values */
    for(i=0; i<sizeof(aCopy)/sizeof(aCopy[0]); i+=2){

      rc = sqlite3BtreeGetMeta(pMain, aCopy[i], &meta);
      if( rc!=SQLITE_OK ) goto end_of_vacuum;
      rc = sqlite3BtreeUpdateMeta(pTemp, aCopy[i], meta+aCopy[i+1]);





    }

    rc = sqlite3BtreeCopyFile(pMain, pTemp);
    if( rc!=SQLITE_OK ) goto end_of_vacuum;
    rc = sqlite3BtreeCommit(pMain);
  }

end_of_vacuum:

Changes to test/vacuum.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
148
149
150
151
152
153
154














































155
156
157
158
159
160
161
...
298
299
300
301
302
303
304

305
#    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 VACUUM statement.
#
# $Id: vacuum.test,v 1.33 2005/02/03 01:08:20 drh 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.
#
................................................................................
do_test vacuum-2.3 {
  cksum
} $cksum
do_test vacuum-2.4 {
  catch {db2 eval {SELECT count(*) FROM sqlite_master}}
  cksum db2
} $cksum















































# Ticket #427.  Make sure VACUUM works when the EMPTY_RESULT_CALLBACKS
# pragma is turned on.
#
do_test vacuum-3.1 {
  db close
  db2 close
................................................................................
    execsql {
      VACUUM;
    }
    cksum
  } $::cksum
}


# finish_test







|







 







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







 







>
|
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
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
...
344
345
346
347
348
349
350
351
352
#    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 VACUUM statement.
#
# $Id: vacuum.test,v 1.34 2005/02/12 00:19:30 drh 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.
#
................................................................................
do_test vacuum-2.3 {
  cksum
} $cksum
do_test vacuum-2.4 {
  catch {db2 eval {SELECT count(*) FROM sqlite_master}}
  cksum db2
} $cksum

# Make sure the schema cookie is incremented by vacuum.
#
do_test vacuum-2.5 {
  execsql {
    BEGIN;
    CREATE TABLE t6 AS SELECT * FROM t1;
    CREATE TABLE t7 AS SELECT * FROM t1;
    COMMIT;
  }
  sqlite3 db3 test.db
  execsql {
    SELECT * FROM t7 LIMIT 1
  } db3
  execsql {
    VACUUM;
  }
  execsql {
    INSERT INTO t7 VALUES(1234567890,'hello','world');
  } db3
  execsql {
    SELECT * FROM t7 WHERE a=1234567890
  }
} {1234567890 hello world}
integrity_check vacuum-2.6
do_test vacuum-2.7 {
  execsql {
    SELECT * FROM t7 WHERE a=1234567890
  } db3
} {1234567890 hello world}
do_test vacuum-2.8 {
  execsql {
    INSERT INTO t7 SELECT * FROM t6;
    SELECT count(*) FROM t7;
  }
} 513
integrity_check vacuum-2.9
do_test vacuum-2.10 {
  execsql {
    DELETE FROM t7;
    SELECT count(*) FROM t7;
  } db3
} 0
integrity_check vacuum-2.11
db3 close
 

# Ticket #427.  Make sure VACUUM works when the EMPTY_RESULT_CALLBACKS
# pragma is turned on.
#
do_test vacuum-3.1 {
  db close
  db2 close
................................................................................
    execsql {
      VACUUM;
    }
    cksum
  } $::cksum
}


finish_test