SQLite

Check-in [b34bde80c7]
Login

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

Overview
Comment:Fix a problem in backup.c causing OsTruncate() to be called with an argument larger than the current file-size. (CVS 6271)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: b34bde80c7e2028baf7ba2ff26e587a63a170f3d
User & Date: danielk1977 2009-02-09 18:55:46.000
Context
2009-02-10
05:45
Fix a bug in test file misc7.test. No code changes. (CVS 6272) (check-in: d919d2a14c user: danielk1977 tags: trunk)
2009-02-09
18:55
Fix a problem in backup.c causing OsTruncate() to be called with an argument larger than the current file-size. (CVS 6271) (check-in: b34bde80c7 user: danielk1977 tags: trunk)
17:34
Add assert() statements to os_unix.c which fire if there is a read or write for the locking region of a database file. (CVS 6270) (check-in: 93e792ffa8 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/backup.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains the implementation of the sqlite3_backup_XXX() 
** API functions and the related features.
**
** $Id: backup.c,v 1.8 2009/02/06 05:59:44 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "btreeInt.h"

/* Macro to find the minimum of two numeric values.
*/
#ifndef MIN







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains the implementation of the sqlite3_backup_XXX() 
** API functions and the related features.
**
** $Id: backup.c,v 1.9 2009/02/09 18:55:46 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "btreeInt.h"

/* Macro to find the minimum of two numeric values.
*/
#ifndef MIN
249
250
251
252
253
254
255

















256
257
258
259
260
261
262
      ((u8 *)sqlite3PagerGetExtra(pDestPg))[0] = 0;
    }
    sqlite3PagerUnref(pDestPg);
  }

  return rc;
}


















/*
** Copy nPage pages from the source b-tree to the destination.
*/
int sqlite3_backup_step(sqlite3_backup *p, int nPage){
  int rc;








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







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
      ((u8 *)sqlite3PagerGetExtra(pDestPg))[0] = 0;
    }
    sqlite3PagerUnref(pDestPg);
  }

  return rc;
}

/*
** If pFile is currently larger than iSize bytes, then truncate it to
** exactly iSize bytes. If pFile is not larger than iSize bytes, then
** this function is a no-op.
**
** Return SQLITE_OK if everything is successful, or an SQLite error 
** code if an error occurs.
*/
static int backupTruncateFile(sqlite3_file *pFile, i64 iSize){
  i64 iCurrent;
  int rc = sqlite3OsFileSize(pFile, &iCurrent);
  if( rc==SQLITE_OK && iCurrent>iSize ){
    rc = sqlite3OsTruncate(pFile, iSize);
  }
  return rc;
}

/*
** Copy nPage pages from the source b-tree to the destination.
*/
int sqlite3_backup_step(sqlite3_backup *p, int nPage){
  int rc;

326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
      }
    }
  
    if( rc==SQLITE_DONE ){
      const int nSrcPagesize = sqlite3BtreeGetPageSize(p->pSrc);
      const int nDestPagesize = sqlite3BtreeGetPageSize(p->pDest);
      int nDestTruncate;
      sqlite3_file *pFile = 0;
      i64 iSize;
  
      /* Update the schema version field in the destination database. This
      ** is to make sure that the schema-version really does change in
      ** the case where the source and destination databases have the
      ** same schema version.
      */
      sqlite3BtreeUpdateMeta(p->pDest, 1, p->iDestSchema+1);







<
<







343
344
345
346
347
348
349


350
351
352
353
354
355
356
      }
    }
  
    if( rc==SQLITE_DONE ){
      const int nSrcPagesize = sqlite3BtreeGetPageSize(p->pSrc);
      const int nDestPagesize = sqlite3BtreeGetPageSize(p->pDest);
      int nDestTruncate;


  
      /* Update the schema version field in the destination database. This
      ** is to make sure that the schema-version really does change in
      ** the case where the source and destination databases have the
      ** same schema version.
      */
      sqlite3BtreeUpdateMeta(p->pDest, 1, p->iDestSchema+1);
369
370
371
372
373
374
375
376
377

378

379
380
381
382
383
384
385
386
387
        **
        **   * The destination may need to be truncated, and
        **
        **   * Data stored on the pages immediately following the 
        **     pending-byte page in the source database may need to be
        **     copied into the destination database.
        */
        iSize = (i64)nSrcPagesize * (i64)nSrcPage;
        pFile = sqlite3PagerFile(pDestPager);

        assert( pFile );

        if( SQLITE_OK==(rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1))
         && SQLITE_OK==(rc = sqlite3OsTruncate(pFile, iSize))
         && SQLITE_OK==(rc = sqlite3PagerSync(pDestPager))
        ){
          i64 iOff;
          i64 iEnd = MIN(PENDING_BYTE + nDestPagesize, iSize);
          for(
            iOff=PENDING_BYTE+nSrcPagesize; 
            rc==SQLITE_OK && iOff<iEnd; 







|
|
>

>

|







384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
        **
        **   * The destination may need to be truncated, and
        **
        **   * Data stored on the pages immediately following the 
        **     pending-byte page in the source database may need to be
        **     copied into the destination database.
        */
        const i64 iSize = (i64)nSrcPagesize * (i64)nSrcPage;
        sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);

        assert( pFile );
        assert( (i64)nDestTruncate*(i64)nDestPagesize >= iSize );
        if( SQLITE_OK==(rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1))
         && SQLITE_OK==(rc = backupTruncateFile(pFile, iSize))
         && SQLITE_OK==(rc = sqlite3PagerSync(pDestPager))
        ){
          i64 iOff;
          i64 iEnd = MIN(PENDING_BYTE + nDestPagesize, iSize);
          for(
            iOff=PENDING_BYTE+nSrcPagesize; 
            rc==SQLITE_OK && iOff<iEnd; 
Changes to test/backup.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2009 January 30
#
# 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 testing the sqlite3_backup_XXX API.
#
# $Id: backup.test,v 1.4 2009/02/06 05:59:45 danielk1977 Exp $

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

#---------------------------------------------------------------------
# Test organization:
#













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2009 January 30
#
# 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 testing the sqlite3_backup_XXX API.
#
# $Id: backup.test,v 1.5 2009/02/09 18:55:46 danielk1977 Exp $

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

#---------------------------------------------------------------------
# Test organization:
#
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
#   * Target database does not include pending-byte page.
#
#   * Target database page-size is the same as the source, OR
#   * Target database page-size is larger than the source, OR
#   * Target database page-size is smaller than the source.
#
set iTest 1
foreach nSrcRow {10 100} {
foreach nDestRow {10 100} {
foreach nDestPgsz {512 1024 2048 4096} {

  catch { file delete test.db }
  catch { file delete test2.db }
  sqlite3 db test.db
  sqlite3 db2 test2.db

  # Set up the content of the two databases.
  #


  foreach {db nRow} [list db $nSrcRow db2 $nDestRow] {
    execsql {
      BEGIN; 
      CREATE TABLE t1(a, b);
      CREATE INDEX i1 ON t1(a, b);

    } $db

    for {set ii 0} {$ii < $nSrcRow} {incr ii} {
      execsql { INSERT INTO t1 VALUES($ii, randstr(1000,1000)) } $db
    }
    execsql COMMIT $db


  }
    
  # Backup the source database.
  do_test backup-3.$iTest.1 {
    sqlite3_backup B db main db2 main
    while {[B step 10]=="SQLITE_OK"} {}
    B finish
  } {SQLITE_OK}
    







|










>
>
|




>

>
|
|
|
|
>
>

|







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
#   * Target database does not include pending-byte page.
#
#   * Target database page-size is the same as the source, OR
#   * Target database page-size is larger than the source, OR
#   * Target database page-size is smaller than the source.
#
set iTest 1
foreach nSrcPg {10 64 65 66 100} {
foreach nDestRow {10 100} {
foreach nDestPgsz {512 1024 2048 4096} {

  catch { file delete test.db }
  catch { file delete test2.db }
  sqlite3 db test.db
  sqlite3 db2 test2.db

  # Set up the content of the two databases.
  #
  execsql { PRAGMA page_size = 1024 }
  execsql "PRAGMA page_size = $nDestPgsz" db2
  foreach db {db db2} {
    execsql {
      BEGIN; 
      CREATE TABLE t1(a, b);
      CREATE INDEX i1 ON t1(a, b);
      COMMIT;
    } $db
  }
  while {[file size test.db]/1024 < $nSrcPg} {
    execsql { INSERT INTO t1 VALUES($ii, randstr(200,200)) }
  }

  for {set ii 0} {$ii < $nDestRow} {incr ii} {
    execsql { INSERT INTO t1 VALUES($ii, randstr(1000,1000)) } db2
  }

  # Backup the source database.
  do_test backup-3.$iTest.1 {
    sqlite3_backup B db main db2 main
    while {[B step 10]=="SQLITE_OK"} {}
    B finish
  } {SQLITE_OK}