SQLite

Check-in [483994a54d]
Login

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

Overview
Comment:Ensure that the sqlite3_scrub_backup() extension creates a backup database at least as large as indicated by the database header, even if the last page of the input database is a free-list leaf.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 483994a54dee3c7a3801e0e9d3c96fa9dbd8d2fd
User & Date: dan 2016-07-26 10:46:21.988
Context
2016-07-27
18:27
When estimating the cost of an index scan, factor in the cost savings of being able to use the index to evaluate some WHERE clause terms without having to do a table lookup. (check-in: a59b5622f7 user: drh tags: improved-index-scan)
16:03
Initialize a variable in where.c to avoid a valgrind warning. (check-in: 4d59df02d3 user: dan tags: trunk)
2016-07-26
18:15
Merge latest trunk changes into this branch. (check-in: d4f3d52c5a user: dan tags: rowvalue)
15:17
Merge fixes to sqlite3_scrub_backup() from trunk. (check-in: 91e811f51e user: drh tags: apple-osx)
10:46
Ensure that the sqlite3_scrub_backup() extension creates a backup database at least as large as indicated by the database header, even if the last page of the input database is a free-list leaf. (check-in: 483994a54d user: dan tags: trunk)
04:49
Copy the cache_spill setting from the main database over to the vacuum_db transient database when running a VACUUM. (check-in: c0e7d98ef2 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to ext/misc/scrub.c.
70
71
72
73
74
75
76

77
78
79
80
81
82
83
  sqlite3 *dbSrc;          /* Source database connection */
  sqlite3_file *pSrc;      /* Source file handle */
  sqlite3 *dbDest;         /* Destination database connection */
  sqlite3_file *pDest;     /* Destination file handle */
  u32 szPage;              /* Page size */
  u32 szUsable;            /* Usable bytes on each page */
  u32 nPage;               /* Number of pages */

  u8 *page1;               /* Content of page 1 */
};

/* Store an error message */
static void scrubBackupErr(ScrubState *p, const char *zFormat, ...){
  va_list ap;
  sqlite3_free(p->zErr);







>







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  sqlite3 *dbSrc;          /* Source database connection */
  sqlite3_file *pSrc;      /* Source file handle */
  sqlite3 *dbDest;         /* Destination database connection */
  sqlite3_file *pDest;     /* Destination file handle */
  u32 szPage;              /* Page size */
  u32 szUsable;            /* Usable bytes on each page */
  u32 nPage;               /* Number of pages */
  u32 iLastPage;           /* Page number of last page written so far*/
  u8 *page1;               /* Content of page 1 */
};

/* Store an error message */
static void scrubBackupErr(ScrubState *p, const char *zFormat, ...){
  va_list ap;
  sqlite3_free(p->zErr);
126
127
128
129
130
131
132

133
134
135
136
137
138
139
  if( p->rcErr ) return;
  iOff = (pgno-1)*(sqlite3_int64)p->szPage;
  rc = p->pDest->pMethods->xWrite(p->pDest, pData, p->szPage, iOff);
  if( rc!=SQLITE_OK ){
    scrubBackupErr(p, "write failed for page %d", pgno);
    p->rcErr = SQLITE_IOERR;
  }

}

/* Prepare a statement against the "db" database. */
static sqlite3_stmt *scrubBackupPrepare(
  ScrubState *p,      /* Backup context */
  sqlite3 *db,        /* Database to prepare against */
  const char *zSql    /* SQL statement */







>







127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
  if( p->rcErr ) return;
  iOff = (pgno-1)*(sqlite3_int64)p->szPage;
  rc = p->pDest->pMethods->xWrite(p->pDest, pData, p->szPage, iOff);
  if( rc!=SQLITE_OK ){
    scrubBackupErr(p, "write failed for page %d", pgno);
    p->rcErr = SQLITE_IOERR;
  }
  if( pgno>p->iLastPage ) p->iLastPage = pgno;
}

/* Prepare a statement against the "db" database. */
static sqlite3_stmt *scrubBackupPrepare(
  ScrubState *p,      /* Backup context */
  sqlite3 *db,        /* Database to prepare against */
  const char *zSql    /* SQL statement */
536
537
538
539
540
541
542














543
544
545
546
547
548
549
       "SELECT rootpage FROM sqlite_master WHERE coalesce(rootpage,0)>0");
  if( pStmt==0 ) goto scrub_abort;
  while( sqlite3_step(pStmt)==SQLITE_ROW ){
    i = (u32)sqlite3_column_int(pStmt, 0);
    scrubBackupBtree(&s, i, 0);
  }
  sqlite3_finalize(pStmt);















scrub_abort:    
  /* Close the destination database without closing the transaction. If we
  ** commit, page zero will be overwritten. */
  sqlite3_close(s.dbDest);

  /* But do close out the read-transaction on the source database */







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







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
564
565
       "SELECT rootpage FROM sqlite_master WHERE coalesce(rootpage,0)>0");
  if( pStmt==0 ) goto scrub_abort;
  while( sqlite3_step(pStmt)==SQLITE_ROW ){
    i = (u32)sqlite3_column_int(pStmt, 0);
    scrubBackupBtree(&s, i, 0);
  }
  sqlite3_finalize(pStmt);

  /* If the last page of the input db file is a free-list leaf, then the
  ** backup file on disk is still smaller than the size indicated within 
  ** the database header. In this case, write a page of zeroes to the 
  ** last page of the backup database so that SQLite does not mistakenly
  ** think the db is corrupt.  */
  if( s.iLastPage<s.nPage ){
    u8 *aZero = scrubBackupAllocPage(&s);
    if( aZero ){
      memset(aZero, 0, s.szPage);
      scrubBackupWrite(&s, s.nPage, aZero);
      sqlite3_free(aZero);
    }
  }

scrub_abort:    
  /* Close the destination database without closing the transaction. If we
  ** commit, page zero will be overwritten. */
  sqlite3_close(s.dbDest);

  /* But do close out the read-transaction on the source database */