/ Check-in [442be135]
Login

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

Overview
Comment:Make sure the change-counter and SQLite-version fields of the header are set correctly even after vacuuming. This is a backport of changes [0be92a7576] and [04fa1e1690] to address ticket [5d863f876ee].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | branch-3.7.4
Files: files | file ages | folders
SHA1: 442be1358e7dff17548718c0c7c031ec320d135d
User & Date: drh 2011-02-20 03:32:54
Original Comment: Make sure the change-counter and SQLite-version fields of the header are set correctly even after vacuuming. This is a backport of changes [0be92a7576] and [04fa1e1690] to address ticket [5de63f876cc].
Context
2011-02-20
03:40
Do not report the database corruption if the the db size header field is greater than the file size on disk unless the two change-counter header fields are identical. Fix for ticket [89b8c9ac54]. Backport by cherrypick of [00c4596f0b270]. check-in: e2616004 user: drh tags: branch-3.7.4
03:32
Make sure the change-counter and SQLite-version fields of the header are set correctly even after vacuuming. This is a backport of changes [0be92a7576] and [04fa1e1690] to address ticket [5d863f876ee]. check-in: 442be135 user: drh tags: branch-3.7.4
03:27
Do not raise an SQLITE_CORRUPT error in Recoverymode if the database size in the header is larger than the physical file size. This is a cherrypick of checkin [114640d920e16c8] check-in: 7701b077 user: drh tags: branch-3.7.4
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/pager.c.

  2911   2911       rc = pagerUndoCallback((void *)pPager, pList->pgno);
  2912   2912       pList = pNext;
  2913   2913     }
  2914   2914   
  2915   2915     return rc;
  2916   2916   }
  2917   2917   
         2918  +
         2919  +/*
         2920  +** Update the value of the change-counter at offsets 24 and 92 in
         2921  +** the header and the sqlite version number at offset 96.
         2922  +**
         2923  +** This is an unconditional update.  See also the pager_incr_changecounter()
         2924  +** routine which only updates the change-counter if the update is actually
         2925  +** needed, as determined by the pPager->changeCountDone state variable.
         2926  +*/
         2927  +static void pager_write_changecounter(PgHdr *pPg){
         2928  +  u32 change_counter;
         2929  +
         2930  +  /* Increment the value just read and write it back to byte 24. */
         2931  +  change_counter = sqlite3Get4byte((u8*)pPg->pPager->dbFileVers)+1;
         2932  +  put32bits(((char*)pPg->pData)+24, change_counter);
         2933  +
         2934  +  /* Also store the SQLite version number in bytes 96..99 and in
         2935  +  ** bytes 92..95 store the change counter for which the version number
         2936  +  ** is valid. */
         2937  +  put32bits(((char*)pPg->pData)+92, change_counter);
         2938  +  put32bits(((char*)pPg->pData)+96, SQLITE_VERSION_NUMBER);
         2939  +}
         2940  +
  2918   2941   /*
  2919   2942   ** This function is a wrapper around sqlite3WalFrames(). As well as logging
  2920   2943   ** the contents of the list of pages headed by pList (connected by pDirty),
  2921   2944   ** this function notifies any active backup processes that the pages have
  2922         -** changed. 
         2945  +** changed.
         2946  +**
         2947  +** The list of pages passed into this routine is always sorted by page number.
         2948  +** Hence, if page 1 appears anywhere on the list, it will be the first page.
  2923   2949   */ 
  2924   2950   static int pagerWalFrames(
  2925   2951     Pager *pPager,                  /* Pager object */
  2926   2952     PgHdr *pList,                   /* List of frames to log */
  2927   2953     Pgno nTruncate,                 /* Database size after this commit */
  2928   2954     int isCommit,                   /* True if this is a commit */
  2929   2955     int syncFlags                   /* Flags to pass to OsSync() (or 0) */
  2930   2956   ){
  2931   2957     int rc;                         /* Return code */
         2958  +#if defined(SQLITE_DEBUG) || defined(SQLITE_CHECK_PAGES)
         2959  +  PgHdr *p;                       /* For looping over pages */
         2960  +#endif
  2932   2961   
  2933   2962     assert( pPager->pWal );
         2963  +#ifdef SQLITE_DEBUG
         2964  +  /* Verify that the page list is in accending order */
         2965  +  for(p=pList; p && p->pDirty; p=p->pDirty){
         2966  +    assert( p->pgno < p->pDirty->pgno );
         2967  +  }
         2968  +#endif
         2969  +
         2970  +  if( pList->pgno==1 ) pager_write_changecounter(pList);
  2934   2971     rc = sqlite3WalFrames(pPager->pWal, 
  2935   2972         pPager->pageSize, pList, nTruncate, isCommit, syncFlags
  2936   2973     );
  2937   2974     if( rc==SQLITE_OK && pPager->pBackup ){
  2938   2975       PgHdr *p;
  2939   2976       for(p=pList; p; p=p->pDirty){
  2940   2977         sqlite3BackupUpdate(pPager->pBackup, p->pgno, (u8 *)p->pData);
  2941   2978       }
  2942   2979     }
  2943   2980   
  2944   2981   #ifdef SQLITE_CHECK_PAGES
  2945         -  {
  2946         -    PgHdr *p;
  2947         -    for(p=pList; p; p=p->pDirty) pager_set_pagehash(p);
         2982  +  for(p=pList; p; p=p->pDirty){
         2983  +    pager_set_pagehash(p);
  2948   2984     }
  2949   2985   #endif
  2950   2986   
  2951   2987     return rc;
  2952   2988   }
  2953   2989   
  2954   2990   /*
................................................................................
  3965   4001       ** set (set by sqlite3PagerDontWrite()).
  3966   4002       */
  3967   4003       if( pgno<=pPager->dbSize && 0==(pList->flags&PGHDR_DONT_WRITE) ){
  3968   4004         i64 offset = (pgno-1)*(i64)pPager->pageSize;   /* Offset to write */
  3969   4005         char *pData;                                   /* Data to write */    
  3970   4006   
  3971   4007         assert( (pList->flags&PGHDR_NEED_SYNC)==0 );
         4008  +      if( pList->pgno==1 ) pager_write_changecounter(pList);
  3972   4009   
  3973   4010         /* Encode the database */
  3974   4011         CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData);
  3975   4012   
  3976   4013         /* Write out the page data. */
  3977   4014         rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset);
  3978   4015   
................................................................................
  5485   5522       pager_set_pagehash(pPg);
  5486   5523     }
  5487   5524   }
  5488   5525   
  5489   5526   /*
  5490   5527   ** This routine is called to increment the value of the database file 
  5491   5528   ** change-counter, stored as a 4-byte big-endian integer starting at 
  5492         -** byte offset 24 of the pager file.
         5529  +** byte offset 24 of the pager file.  The secondary change counter at
         5530  +** 92 is also updated, as is the SQLite version number at offset 96.
         5531  +**
         5532  +** But this only happens if the pPager->changeCountDone flag is false.
         5533  +** To avoid excess churning of page 1, the update only happens once.
         5534  +** See also the pager_write_changecounter() routine that does an 
         5535  +** unconditional update of the change counters.
  5493   5536   **
  5494   5537   ** If the isDirectMode flag is zero, then this is done by calling 
  5495   5538   ** sqlite3PagerWrite() on page 1, then modifying the contents of the
  5496   5539   ** page data. In this case the file will be updated when the current
  5497   5540   ** transaction is committed.
  5498   5541   **
  5499   5542   ** The isDirectMode flag may only be non-zero if the library was compiled
................................................................................
  5526   5569     UNUSED_PARAMETER(isDirectMode);
  5527   5570   #else
  5528   5571   # define DIRECT_MODE isDirectMode
  5529   5572   #endif
  5530   5573   
  5531   5574     if( !pPager->changeCountDone && pPager->dbSize>0 ){
  5532   5575       PgHdr *pPgHdr;                /* Reference to page 1 */
  5533         -    u32 change_counter;           /* Initial value of change-counter field */
  5534   5576   
  5535   5577       assert( !pPager->tempFile && isOpen(pPager->fd) );
  5536   5578   
  5537   5579       /* Open page 1 of the file for writing. */
  5538   5580       rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
  5539   5581       assert( pPgHdr==0 || rc==SQLITE_OK );
  5540   5582   
  5541   5583       /* If page one was fetched successfully, and this function is not
  5542   5584       ** operating in direct-mode, make page 1 writable.  When not in 
  5543   5585       ** direct mode, page 1 is always held in cache and hence the PagerGet()
  5544   5586       ** above is always successful - hence the ALWAYS on rc==SQLITE_OK.
  5545   5587       */
  5546         -    if( !DIRECT_MODE && ALWAYS(rc==SQLITE_OK) ){
         5588  +    if( !DIRECT_MODE && rc==SQLITE_OK ){
  5547   5589         rc = sqlite3PagerWrite(pPgHdr);
  5548   5590       }
  5549   5591   
  5550   5592       if( rc==SQLITE_OK ){
  5551         -      /* Increment the value just read and write it back to byte 24. */
  5552         -      change_counter = sqlite3Get4byte((u8*)pPager->dbFileVers);
  5553         -      change_counter++;
  5554         -      put32bits(((char*)pPgHdr->pData)+24, change_counter);
  5555         -
  5556         -      /* Also store the SQLite version number in bytes 96..99 and in
  5557         -      ** bytes 92..95 store the change counter for which the version number
  5558         -      ** is valid. */
  5559         -      put32bits(((char*)pPgHdr->pData)+92, change_counter);
  5560         -      put32bits(((char*)pPgHdr->pData)+96, SQLITE_VERSION_NUMBER);
         5593  +      /* Actually do the update of the change counter */
         5594  +      pager_write_changecounter(pPgHdr);
  5561   5595   
  5562   5596         /* If running in direct mode, write the contents of page 1 to the file. */
  5563   5597         if( DIRECT_MODE ){
  5564   5598           const void *zBuf;
  5565   5599           assert( pPager->dbFileSize>0 );
  5566   5600           CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM, zBuf);
  5567   5601           if( rc==SQLITE_OK ){

Changes to test/exclusive2.test.

   295    295   } {4}
   296    296   do_test exclusive2-3.5 {
   297    297     execsql {
   298    298       PRAGMA locking_mode = normal;
   299    299       INSERT INTO t1 VALUES(randstr(10, 400));
   300    300     }
   301    301     readPagerChangeCounter test.db
   302         -} {4}
          302  +} {5}
   303    303   do_test exclusive2-3.6 {
   304    304     execsql {
   305    305       INSERT INTO t1 VALUES(randstr(10, 400));
   306    306     }
   307    307     readPagerChangeCounter test.db
   308         -} {5}
          308  +} {6}
   309    309   sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)
   310    310   
   311    311   finish_test