Index: src/backup.c ================================================================== --- src/backup.c +++ src/backup.c @@ -215,11 +215,11 @@ assert( zSrcData ); /* Catch the case where the destination is an in-memory database and the ** page sizes of the source and destination differ. */ - if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(sqlite3BtreePager(p->pDest)) ){ + if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){ rc = SQLITE_READONLY; } /* This loop runs once for each destination page spanned by the source ** page. For each iteration, variable iOff is set to the byte offset @@ -285,18 +285,31 @@ /* ** Copy nPage pages from the source b-tree to the destination. */ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ int rc; + int destMode; /* Destination journal mode */ + int pgszSrc; /* Source page size */ + int pgszDest; /* Destination page size */ sqlite3_mutex_enter(p->pSrcDb->mutex); sqlite3BtreeEnter(p->pSrc); if( p->pDestDb ){ sqlite3_mutex_enter(p->pDestDb->mutex); } - rc = p->rc; + /* Do not allow backup if the destination database is in WAL mode */ + destMode = sqlite3PagerJournalMode(sqlite3BtreePager(p->pDest), + PAGER_JOURNALMODE_QUERY); + pgszSrc = sqlite3BtreeGetPageSize(p->pSrc); + pgszDest = sqlite3BtreeGetPageSize(p->pDest); + if( destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){ + rc = SQLITE_READONLY; + }else{ + rc = p->rc; + } + if( !isFatalError(rc) ){ Pager * const pSrcPager = sqlite3BtreePager(p->pSrc); /* Source pager */ Pager * const pDestPager = sqlite3BtreePager(p->pDest); /* Dest pager */ int ii; /* Iterator variable */ int nSrcPage = -1; /* Size of source db in pages */ @@ -361,12 +374,10 @@ ** same schema version. */ if( rc==SQLITE_DONE && (rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1))==SQLITE_OK ){ - const int nSrcPagesize = sqlite3BtreeGetPageSize(p->pSrc); - const int nDestPagesize = sqlite3BtreeGetPageSize(p->pDest); int nDestTruncate; if( p->pDestDb ){ sqlite3ResetInternalSchema(p->pDestDb, 0); } @@ -381,56 +392,58 @@ ** sqlite3PagerTruncateImage() here so that any pages in the ** destination file that lie beyond the nDestTruncate page mark are ** journalled by PagerCommitPhaseOne() before they are destroyed ** by the file truncation. */ - if( nSrcPagesizepSrc) ); + assert( pgszDest==sqlite3BtreeGetPageSize(p->pDest) ); + if( pgszSrcpDest->pBt) ){ nDestTruncate--; } }else{ - nDestTruncate = nSrcPage * (nSrcPagesize/nDestPagesize); + nDestTruncate = nSrcPage * (pgszSrc/pgszDest); } sqlite3PagerTruncateImage(pDestPager, nDestTruncate); - if( nSrcPagesize= iSize || ( + assert( (i64)nDestTruncate*(i64)pgszDest >= iSize || ( nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1) - && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+nDestPagesize + && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest )); 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); + i64 iEnd = MIN(PENDING_BYTE + pgszDest, iSize); for( - iOff=PENDING_BYTE+nSrcPagesize; + iOff=PENDING_BYTE+pgszSrc; rc==SQLITE_OK && iOff +**
  • the destination database was opened read-only, or +**
  • the destination database is using write-ahead-log journaling +** and the destination and source page sizes differ, or +**
  • The destination database is an in-memory database and the +** destination and source page sizes differ. +** )^ ** ** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then ** the [sqlite3_busy_handler | busy-handler function] ** is invoked (if one is specified). ^If the ** busy-handler returns non-zero before the lock is available, then