/ Check-in [7bd44794]
Login

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

Overview
Comment:Prohibit backup if the destination is using WAL and has a different page size from the source.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 7bd44794c482beee16c684712545275e2bf63dfa
User & Date: drh 2010-05-05 16:23:27
References
2010-05-05
18:46
Do not compare page sizes on source and destination of backup until transactions are started and the page sizes are locked. This is a fix to check-in [7bd44794c4]. check-in: ec715778 user: drh tags: trunk
Context
2010-05-05
18:20
Simplifications to the SHM locking implementation in os_unix.c. check-in: 9de05bfb user: drh tags: trunk
16:23
Prohibit backup if the destination is using WAL and has a different page size from the source. check-in: 7bd44794 user: drh tags: trunk
15:33
When closing a WAL database, if the exclusive lock on the database file is obtained and the database successfully checkpointed, delete the wal-index file from the file system. check-in: 2ac5d96c user: dan tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/backup.c.

   213    213     assert( !isFatalError(p->rc) );
   214    214     assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) );
   215    215     assert( zSrcData );
   216    216   
   217    217     /* Catch the case where the destination is an in-memory database and the
   218    218     ** page sizes of the source and destination differ. 
   219    219     */
   220         -  if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(sqlite3BtreePager(p->pDest)) ){
          220  +  if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){
   221    221       rc = SQLITE_READONLY;
   222    222     }
   223    223   
   224    224     /* This loop runs once for each destination page spanned by the source 
   225    225     ** page. For each iteration, variable iOff is set to the byte offset
   226    226     ** of the destination page.
   227    227     */
................................................................................
   283    283   }
   284    284   
   285    285   /*
   286    286   ** Copy nPage pages from the source b-tree to the destination.
   287    287   */
   288    288   int sqlite3_backup_step(sqlite3_backup *p, int nPage){
   289    289     int rc;
          290  +  int destMode;       /* Destination journal mode */
          291  +  int pgszSrc;        /* Source page size */
          292  +  int pgszDest;       /* Destination page size */
   290    293   
   291    294     sqlite3_mutex_enter(p->pSrcDb->mutex);
   292    295     sqlite3BtreeEnter(p->pSrc);
   293    296     if( p->pDestDb ){
   294    297       sqlite3_mutex_enter(p->pDestDb->mutex);
   295    298     }
   296    299   
   297         -  rc = p->rc;
          300  +  /* Do not allow backup if the destination database is in WAL mode */
          301  +  destMode = sqlite3PagerJournalMode(sqlite3BtreePager(p->pDest),
          302  +                                     PAGER_JOURNALMODE_QUERY);
          303  +  pgszSrc = sqlite3BtreeGetPageSize(p->pSrc);
          304  +  pgszDest = sqlite3BtreeGetPageSize(p->pDest);
          305  +  if( destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){
          306  +    rc = SQLITE_READONLY;
          307  +  }else{
          308  +    rc = p->rc;
          309  +  }
          310  +
   298    311     if( !isFatalError(rc) ){
   299    312       Pager * const pSrcPager = sqlite3BtreePager(p->pSrc);     /* Source pager */
   300    313       Pager * const pDestPager = sqlite3BtreePager(p->pDest);   /* Dest pager */
   301    314       int ii;                            /* Iterator variable */
   302    315       int nSrcPage = -1;                 /* Size of source db in pages */
   303    316       int bCloseTrans = 0;               /* True if src db requires unlocking */
   304    317   
................................................................................
   359    372       ** is to make sure that the schema-version really does change in
   360    373       ** the case where the source and destination databases have the
   361    374       ** same schema version.
   362    375       */
   363    376       if( rc==SQLITE_DONE 
   364    377        && (rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1))==SQLITE_OK
   365    378       ){
   366         -      const int nSrcPagesize = sqlite3BtreeGetPageSize(p->pSrc);
   367         -      const int nDestPagesize = sqlite3BtreeGetPageSize(p->pDest);
   368    379         int nDestTruncate;
   369    380     
   370    381         if( p->pDestDb ){
   371    382           sqlite3ResetInternalSchema(p->pDestDb, 0);
   372    383         }
   373    384   
   374    385         /* Set nDestTruncate to the final number of pages in the destination
................................................................................
   379    390         ** round up. In this case the call to sqlite3OsTruncate() below will
   380    391         ** fix the size of the file. However it is important to call
   381    392         ** sqlite3PagerTruncateImage() here so that any pages in the 
   382    393         ** destination file that lie beyond the nDestTruncate page mark are
   383    394         ** journalled by PagerCommitPhaseOne() before they are destroyed
   384    395         ** by the file truncation.
   385    396         */
   386         -      if( nSrcPagesize<nDestPagesize ){
   387         -        int ratio = nDestPagesize/nSrcPagesize;
          397  +      assert( pgszSrc==sqlite3BtreeGetPageSize(p->pSrc) );
          398  +      assert( pgszDest==sqlite3BtreeGetPageSize(p->pDest) );
          399  +      if( pgszSrc<pgszDest ){
          400  +        int ratio = pgszDest/pgszSrc;
   388    401           nDestTruncate = (nSrcPage+ratio-1)/ratio;
   389    402           if( nDestTruncate==(int)PENDING_BYTE_PAGE(p->pDest->pBt) ){
   390    403             nDestTruncate--;
   391    404           }
   392    405         }else{
   393         -        nDestTruncate = nSrcPage * (nSrcPagesize/nDestPagesize);
          406  +        nDestTruncate = nSrcPage * (pgszSrc/pgszDest);
   394    407         }
   395    408         sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
   396    409   
   397         -      if( nSrcPagesize<nDestPagesize ){
          410  +      if( pgszSrc<pgszDest ){
   398    411           /* If the source page-size is smaller than the destination page-size,
   399    412           ** two extra things may need to happen:
   400    413           **
   401    414           **   * The destination may need to be truncated, and
   402    415           **
   403    416           **   * Data stored on the pages immediately following the 
   404    417           **     pending-byte page in the source database may need to be
   405    418           **     copied into the destination database.
   406    419           */
   407         -        const i64 iSize = (i64)nSrcPagesize * (i64)nSrcPage;
          420  +        const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
   408    421           sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
   409    422   
   410    423           assert( pFile );
   411         -        assert( (i64)nDestTruncate*(i64)nDestPagesize >= iSize || (
          424  +        assert( (i64)nDestTruncate*(i64)pgszDest >= iSize || (
   412    425                 nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
   413         -           && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+nDestPagesize
          426  +           && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
   414    427           ));
   415    428           if( SQLITE_OK==(rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1))
   416    429            && SQLITE_OK==(rc = backupTruncateFile(pFile, iSize))
   417    430            && SQLITE_OK==(rc = sqlite3PagerSync(pDestPager))
   418    431           ){
   419    432             i64 iOff;
   420         -          i64 iEnd = MIN(PENDING_BYTE + nDestPagesize, iSize);
          433  +          i64 iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
   421    434             for(
   422         -            iOff=PENDING_BYTE+nSrcPagesize; 
          435  +            iOff=PENDING_BYTE+pgszSrc; 
   423    436               rc==SQLITE_OK && iOff<iEnd; 
   424         -            iOff+=nSrcPagesize
          437  +            iOff+=pgszSrc
   425    438             ){
   426    439               PgHdr *pSrcPg = 0;
   427         -            const Pgno iSrcPg = (Pgno)((iOff/nSrcPagesize)+1);
          440  +            const Pgno iSrcPg = (Pgno)((iOff/pgszSrc)+1);
   428    441               rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
   429    442               if( rc==SQLITE_OK ){
   430    443                 u8 *zData = sqlite3PagerGetData(pSrcPg);
   431         -              rc = sqlite3OsWrite(pFile, zData, nSrcPagesize, iOff);
          444  +              rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
   432    445               }
   433    446               sqlite3PagerUnref(pSrcPg);
   434    447             }
   435    448           }
   436    449         }else{
   437    450           rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0);
   438    451         }

Changes to src/sqlite.h.in.

  5485   5485   ** from source to destination, then it returns [SQLITE_DONE].
  5486   5486   ** ^If an error occurs while running sqlite3_backup_step(B,N),
  5487   5487   ** then an [error code] is returned. ^As well as [SQLITE_OK] and
  5488   5488   ** [SQLITE_DONE], a call to sqlite3_backup_step() may return [SQLITE_READONLY],
  5489   5489   ** [SQLITE_NOMEM], [SQLITE_BUSY], [SQLITE_LOCKED], or an
  5490   5490   ** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX] extended error code.
  5491   5491   **
  5492         -** ^The sqlite3_backup_step() might return [SQLITE_READONLY] if the destination
  5493         -** database was opened read-only or if
  5494         -** the destination is an in-memory database with a different page size
  5495         -** from the source database.
         5492  +** ^(The sqlite3_backup_step() might return [SQLITE_READONLY] if
         5493  +** <ol>
         5494  +** <li> the destination database was opened read-only, or
         5495  +** <li> the destination database is using write-ahead-log journaling
         5496  +** and the destination and source page sizes differ, or
         5497  +** <li> The destination database is an in-memory database and the
         5498  +** destination and source page sizes differ.
         5499  +** </ol>)^
  5496   5500   **
  5497   5501   ** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then
  5498   5502   ** the [sqlite3_busy_handler | busy-handler function]
  5499   5503   ** is invoked (if one is specified). ^If the 
  5500   5504   ** busy-handler returns non-zero before the lock is available, then 
  5501   5505   ** [SQLITE_BUSY] is returned to the caller. ^In this case the call to
  5502   5506   ** sqlite3_backup_step() can be retried later. ^If the source