]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Revert the fixes to backup in [1f940357f7] and [e5db80350c] and instead fix the probl...
authordan <Dan Kennedy>
Wed, 24 Jun 2026 11:50:08 +0000 (11:50 +0000)
committerdan <Dan Kennedy>
Wed, 24 Jun 2026 11:50:08 +0000 (11:50 +0000)
FossilOrigin-Name: 44a0f396daa13f382fd839cd8be49148aa24114968b97fed7f365307d1f8280a

manifest
manifest.tags
manifest.uuid
src/backup.c
src/btree.h
src/build.c
src/vacuum.c
test/backup5.test

index 1c86e1dc7c8fe6bff4c3f90b417151ea547a3fb0..9cf33c6e2c87d430826b77e7c93fe2b9f32b95cc 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Swap\stwo\slines\sto\sget\sthe\samalgamation\sbuilding\sagain\swith\sSQLITE_OMIT_FLOATING_POINT,\snoting\sthat\sneither\sthe\sshell\snor\sthe\scanonical\slibrary\sbuild\swith\sthat\sflag.\sReported\sin\s[forum:8c3df4da0d|forum\spost\s2026-06-24T07:21:05Z].
-D 2026-06-24T10:22:36.339
+C Revert\sthe\sfixes\sto\sbackup\sin\s[1f940357f7]\sand\s[e5db80350c]\sand\sinstead\sfix\sthe\sproblem\sreported\sby\sforum\spost\s[forum:15d82885e2\s|\s15d82885e2]\s(that\sa\scall\sto\ssqlite3_deserialize()\safter\ssqlite3_backup_init()\sbut\sbefore\sthe\sfirst\scall\sto\ssqlite3_backup_step()\son\sthe\sdestination\sdb\sof\sa\sbackup\scould\scause\sa\scrash)\sby\sdeferring\scaching\sthe\spointer\sto\sthe\sdestination\sBtree\suntil\safter\sit\sis\slocked.\sThis\saddresses\sbug\s[bugs:/info/2026-06-24T08:41:13Z\s|\s2026-06-24T08:41:13Z].
+D 2026-06-24T11:50:08.765
 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
@@ -674,13 +674,13 @@ F src/alter.c da59ac700b52ba5d0e4dd099fb1818975cf8a79a546594da586b4e1eba3ae405
 F src/analyze.c 73162482c656187823217f4c00758c9ee13a420c8745bc542129e0279b792287
 F src/attach.c c58278c7d2d954785591c4fde81669ec3e4d52f348c453b028a19ae8adf4f338
 F src/auth.c b5ece4e1edccad082c0332fa0087df225473bae0feea9269f824312201377185
-F src/backup.c 2f5f350c714407a04fadc9c812b8fcbb47d472c543c492f9fc03043c94255406
+F src/backup.c 89de631678bcbb3ad46f8a8bb43fe4b87b8ada42accd1fe5def363d352ac26d3
 F src/bitvec.c e242d4496774dfc88fa278177dd23b607dce369ccafb3f61b41638eea2c9b399
 F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea
 F src/btree.c 515cf62220ceb483ba9a31ebb3d7565ea9d63ffc3d61bb974b2815fef393df0e
-F src/btree.h c3ba6ba663e185b265a327165bd795e6dc7806fe5a75fe9f547a8459c96f73a7
+F src/btree.h 2ee0ddfdf4f8530ad1d46afffd7da21a0e243bfab10973011ac6f6b7fb4109a1
 F src/btreeInt.h 4f512ad31083216b6789762d4c345b73367985d3b39421c9ba7c0902d09fb38b
-F src/build.c 09946336c3011c2ae2faccdf04e33336e1cd51fd836651be0cd7eb5814f7f6a0
+F src/build.c 0a06d413b17a5d7ff80a8499c413e7e3e50cd96f161c4d400462cb8416698c06
 F src/callback.c 3605bbf02bd7ed46c79cd48346db4a32fc51d67624400539c0532f4eead804ad
 F src/carray.c 3efe3982d5fb323334c29328a4e189ccaef6b95612a6084ad5fa124fd5db1179
 F src/complete.c f216b970ce99c5a657556cf1f17e7ddd494515d3beb63df426bf59ff43bd3d9a
@@ -803,7 +803,7 @@ F src/update.c 3e5e7ff66fa19ebe4d1b113d480639a24cc1175adbefabbd1a948a07f28e37cf
 F src/upsert.c dd9f0fcccbfb4f20e1026a21a7254ba3f2c08e9cfa92affaff5b5ec3b00ea549
 F src/utf.c 7267c3fb9e2467020507601af3354c2446c61f444387e094c779dccd5ca62165
 F src/util.c c069caa2e85389deeda302b792161dc536d50c401dd447269e4934aca8f6790c
-F src/vacuum.c 4eda73a75a15f939b45b26e189f5b25757b39d7cb6d5e972a7f754e75d019189
+F src/vacuum.c d3d35d8ae893d419ade5fa196d761a83bddcbb62137a1a157ae751ef38b26e82
 F src/vdbe.c 6397694fa506aa1841dc8bb6a17c514aa602a4ad2515024fcd5880558c1ef57f
 F src/vdbe.h 70e862ac8a11b590f8c1eaac17a0078429d42bc4ea3f757a9af0f451dd966a71
 F src/vdbeInt.h c31ba4dc8d280c2b1dc89c6fcee68f2555e3813ab34279552c20b964c0e338b1
@@ -899,7 +899,7 @@ F test/backcompat.test f2431465ed668f09fc3f6998e56e893a1506ccea6e8b6f409f085f759
 F test/backup.test 3b08fd4af69f0fa786931103a31f4542b184aba16e239e5f22b18c3c2476697f
 F test/backup2.test b153553ee5667b0748b43346b0725fbf80ce1f5544613bf087d669778b60ec56
 F test/backup4.test 8f6fd48e0dfde77b9a3bb26dc471ede3e101df32
-F test/backup5.test 3e16065dc45c40030378702aac3e92f4d6e7d8853f0328f0390c9e7a71d8c712
+F test/backup5.test a0716934a41bea622c5f1928d00c23093e986c3dfc58aaca9db3b431c66276dc
 F test/backup_ioerr.test 4c3c7147cee85b024ecf6e150e090c32fdbb5135
 F test/backup_malloc.test 0c9abdf74c51e7bedb66d504cd684f28d4bd4027
 F test/badutf.test cff75b714866a4ffa0cdda252eb8fe8765483f5872c0076223c92d52b4fffd1b
@@ -2208,8 +2208,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee
 F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
 F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c
-P e458ed9cc9d46dfdade3b4e99eb209d8aefd40a245e002d68df1813f9f99e2d7
-R 592bd4e6bc47a54bee1f0be621a913e3
-U stephan
-Z 56bbc5d496907534eef40aa7c99dc40d
+P 23936786e680131af644510eb50b7ad20ee39221d1fb29732dea76483aed2273
+R e0e0f7b38815f812e27f687f577ea44f
+T *branch * attach-backup-fix
+T *sym-attach-backup-fix *
+T -sym-trunk *
+U dan
+Z df2c9c70dcdd169082f93f43b6437c36
 # Remove this line to create a well-formed Fossil manifest.
index bec971799ff1b8ee641c166c7aeb22d12c785393..5932301b495af5939c0fd836e6a880fe0add33dc 100644 (file)
@@ -1,2 +1,2 @@
-branch trunk
-tag trunk
+branch attach-backup-fix
+tag attach-backup-fix
index 6f73e7e51ec79e877352c92041c34c256acc98c7..b60937e3a0269cac270af94968fb6ada6a1b2e17 100644 (file)
@@ -1 +1 @@
-23936786e680131af644510eb50b7ad20ee39221d1fb29732dea76483aed2273
+44a0f396daa13f382fd839cd8be49148aa24114968b97fed7f365307d1f8280a
index 0a20ae4cf9fdd417e8aca7b8ca329acfb1b3ee4a..c46d896293795bb77e0b868f88529ac3c69310d3 100644 (file)
 */
 struct sqlite3_backup {
   sqlite3* pDestDb;        /* Destination database handle */
-  int iDest;               /* Destination db file */
+  char *zDestDb;
+  Btree *pDest;            /* Destination b-tree file */
   u32 iDestSchema;         /* Original schema cookie in destination */
   int bDestLocked;         /* True once a write-transaction is open on pDest */
 
   Pgno iNext;              /* Page number of the next source page to copy */
   sqlite3* pSrcDb;         /* Source database handle */
-  int iSrc;                /* Source db file */
+  Btree *pSrc;             /* Source b-tree file */
 
   int rc;                  /* Backup process error code */
 
@@ -40,20 +41,6 @@ struct sqlite3_backup {
   sqlite3_backup *pNext;   /* Next backup associated with source pager */
 };
 
-/*
-** Return the source (Btree*) used by backup object b.
-*/
-#define getSourceBtree(b) ((b)->pSrcDb->aDb[(b)->iSrc].pBt)
-
-/*
-** Return the destination (Btree*) used by backup object b.
-*/
-#define getDestBtree(b) ( (b)->pDestDb ?   \
-    (b)->pDestDb->aDb[(b)->iDest].pBt :    \
-    (b)->pSrcDb->aDb[(b)->iDest].pBt       \
-)
-
-
 /*
 ** THREAD SAFETY NOTES:
 **
@@ -85,15 +72,15 @@ struct sqlite3_backup {
 */
 
 /*
-** Return an integer corresponding to database zDb (i.e. "main", "temp")
+** Return a pointer corresponding to database zDb (i.e. "main", "temp")
 ** in connection handle pDb. If such a database cannot be found, return
-** a negative value and write an error message to pErrorDb.
+** a NULL pointer and write an error message to pErrorDb.
 **
 ** If the "temp" database is requested, it may need to be opened by this 
-** function. If an error occurs while doing so, return -1 and write an 
+** function. If an error occurs while doing so, return 0 and write an 
 ** error message to pErrorDb.
 */
-static int findDatabase(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
+static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
   int i = sqlite3FindDbName(pDb, zDb);
 
   if( i==1 ){
@@ -107,25 +94,24 @@ static int findDatabase(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
     sqlite3DbFree(pErrorDb, sParse.zErrMsg);
     sqlite3ParseObjectReset(&sParse);
     if( rc ){
-      return -1;
+      return 0;
     }
   }
 
   if( i<0 ){
     sqlite3ErrorWithMsg(pErrorDb, SQLITE_ERROR, "unknown database %s", zDb);
+    return 0;
   }
 
-  return i;
+  return pDb->aDb[i].pBt;
 }
 
 /*
 ** Attempt to set the page size of the destination to match the page size
 ** of the source.
 */
-static int setDestPgsz(sqlite3_backup *p){
-  return sqlite3BtreeSetPageSize(getDestBtree(p), 
-      sqlite3BtreeGetPageSize(getSourceBtree(p)), 0, 0
-  );
+static int setDestPgsz(Btree *pDest, Btree *pSrc){
+  return sqlite3BtreeSetPageSize(pDest, sqlite3BtreeGetPageSize(pSrc), 0, 0);
 }
 
 /*
@@ -182,27 +168,37 @@ sqlite3_backup *sqlite3_backup_init(
     );
     p = 0;
   }else {
+    int nDest = sqlite3Strlen30(zDestDb);
+
     /* Allocate space for a new sqlite3_backup object...
     ** EVIDENCE-OF: R-64852-21591 The sqlite3_backup object is created by a
     ** call to sqlite3_backup_init() and is destroyed by a call to
     ** sqlite3_backup_finish(). */
-    p = (sqlite3_backup *)sqlite3MallocZero(sizeof(sqlite3_backup));
+    p = (sqlite3_backup*)sqlite3MallocZero(sizeof(sqlite3_backup)+nDest+1);
     if( !p ){
       sqlite3Error(pDestDb, SQLITE_NOMEM_BKPT);
+    }else{
+      p->zDestDb = (char*)&p[1];
+      memcpy(p->zDestDb, zDestDb, nDest);
     }
   }
 
   /* If the allocation succeeded, populate the new object. */
   if( p ){
-    p->iDest = findDatabase(pDestDb, pDestDb, zDestDb); 
-    p->iSrc = findDatabase(pDestDb, pSrcDb, zSrcDb);
+    /* Do not store the pointer to the destination b-tree at this point.
+    ** This is because there is nothing preventing it from being detached
+    ** or otherwise freed before the first call to sqlite3_backup_step()
+    ** on this object. The source b-tree does not have this problem, as
+    ** incrementing Btree.nBackup (see below) effectively locks the object. */
+    Btree *pDest = findBtree(pDestDb, pDestDb, zDestDb);
+    p->pSrc = findBtree(pDestDb, pSrcDb, zSrcDb);
     p->pDestDb = pDestDb;
     p->pSrcDb = pSrcDb;
     p->iNext = 1;
     p->isAttached = 0;
 
-    if( p->iSrc<0 || p->iDest<0
-     || checkReadTransaction(pDestDb, getDestBtree(p))!=SQLITE_OK 
+    if( 0==p->pSrc || 0==pDest 
+     || checkReadTransaction(pDestDb, pDest)!=SQLITE_OK 
      ){
       /* One (or both) of the named databases did not exist or an OOM
       ** error was hit. Or there is a transaction open on the destination
@@ -214,7 +210,7 @@ sqlite3_backup *sqlite3_backup_init(
     }
   }
   if( p ){
-    getSourceBtree(p)->nBackup++;
+    p->pSrc->nBackup++;
   }
 
   sqlite3_mutex_leave(pDestDb->mutex);
@@ -242,19 +238,18 @@ static int backupOnePage(
   const u8 *zSrcData,             /* Source database page data */
   int bUpdate                     /* True for an update, false otherwise */
 ){
-  Btree *pDestBt = getDestBtree(p);
-  Pager * const pDestPager = sqlite3BtreePager(pDestBt);
-  const int nSrcPgsz = sqlite3BtreeGetPageSize(getSourceBtree(p));
-  int nDestPgsz = sqlite3BtreeGetPageSize(pDestBt);
+  Pager * const pDestPager = sqlite3BtreePager(p->pDest);
+  const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc);
+  int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest);
   const int nCopy = MIN(nSrcPgsz, nDestPgsz);
   const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz;
   int rc = SQLITE_OK;
   i64 iOff;
 
-  assert( sqlite3BtreeGetReserveNoMutex(getSourceBtree(p))>=0 );
+  assert( sqlite3BtreeGetReserveNoMutex(p->pSrc)>=0 );
   assert( p->bDestLocked );
   assert( !isFatalError(p->rc) );
-  assert( iSrcPg!=PENDING_BYTE_PAGE(getSourceBtree(p)->pBt) );
+  assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) );
   assert( zSrcData );
   assert( nSrcPgsz==nDestPgsz || sqlite3PagerIsMemdb(pDestPager)==0 );
 
@@ -265,7 +260,7 @@ static int backupOnePage(
   for(iOff=iEnd-(i64)nSrcPgsz; rc==SQLITE_OK && iOff<iEnd; iOff+=nDestPgsz){
     DbPage *pDestPg = 0;
     Pgno iDest = (Pgno)(iOff/nDestPgsz)+1;
-    if( iDest==PENDING_BYTE_PAGE(pDestBt->pBt) ) continue;
+    if( iDest==PENDING_BYTE_PAGE(p->pDest->pBt) ) continue;
     if( SQLITE_OK==(rc = sqlite3PagerGet(pDestPager, iDest, &pDestPg, 0))
      && SQLITE_OK==(rc = sqlite3PagerWrite(pDestPg))
     ){
@@ -283,7 +278,7 @@ static int backupOnePage(
       memcpy(zOut, zIn, nCopy);
       ((u8 *)sqlite3PagerGetExtra(pDestPg))[0] = 0;
       if( iOff==0 && bUpdate==0 ){
-        sqlite3Put4byte(&zOut[28], sqlite3BtreeLastPage(getSourceBtree(p)));
+        sqlite3Put4byte(&zOut[28], sqlite3BtreeLastPage(p->pSrc));
       }
     }
     sqlite3PagerUnref(pDestPg);
@@ -315,8 +310,8 @@ static int backupTruncateFile(sqlite3_file *pFile, i64 iSize){
 */
 static void attachBackupObject(sqlite3_backup *p){
   sqlite3_backup **pp;
-  assert( sqlite3BtreeHoldsMutex(getSourceBtree(p)) );
-  pp = sqlite3PagerBackupPtr(sqlite3BtreePager(getSourceBtree(p)));
+  assert( sqlite3BtreeHoldsMutex(p->pSrc) );
+  pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc));
   p->pNext = *pp;
   *pp = p;
   p->isAttached = 1;
@@ -330,26 +325,21 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
   int destMode;       /* Destination journal mode */
   int pgszSrc = 0;    /* Source page size */
   int pgszDest = 0;   /* Destination page size */
-  Btree *pDest;
-  Btree *pSrc;
 
 #ifdef SQLITE_ENABLE_API_ARMOR
   if( p==0 ) return SQLITE_MISUSE_BKPT;
 #endif
-  assert( p->iDest>=0 );
-  assert( p->iSrc>=0 );
-  pDest = getDestBtree(p);
-  pSrc = getSourceBtree(p);
   sqlite3_mutex_enter(p->pSrcDb->mutex);
-  sqlite3BtreeEnter(pSrc);
+  sqlite3BtreeEnter(p->pSrc);
   if( p->pDestDb ){
     sqlite3_mutex_enter(p->pDestDb->mutex);
   }
 
   rc = p->rc;
   if( !isFatalError(rc) ){
-    Pager * const pSrcPager = sqlite3BtreePager(pSrc);     /* Source pager */
-    Pager * const pDestPager = sqlite3BtreePager(pDest);   /* Dest pager */
+    Pager * const pSrcPager = sqlite3BtreePager(p->pSrc);     /* Source pager */
+    Btree * pDest = 0;                                        /* Dest btree */
+    Pager * pDestPager = 0;                                   /* Dest pager */
     int ii;                            /* Iterator variable */
     int nSrcPage = -1;                 /* Size of source db in pages */
     int bCloseTrans = 0;               /* True if src db requires unlocking */
@@ -357,28 +347,41 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
     /* If the source pager is currently in a write-transaction, return
     ** SQLITE_BUSY immediately.
     */
-    if( p->pDestDb && pSrc->pBt->inTransaction==TRANS_WRITE ){
+    if( p->pDestDb && p->pSrc->pBt->inTransaction==TRANS_WRITE ){
       rc = SQLITE_BUSY;
     }else{
       rc = SQLITE_OK;
     }
 
+
     /* If there is no open read-transaction on the source database, open
     ** one now. If a transaction is opened here, then it will be closed
     ** before this function exits.
     */
-    if( rc==SQLITE_OK && SQLITE_TXN_NONE==sqlite3BtreeTxnState(pSrc) ){
-      rc = sqlite3BtreeBeginTrans(pSrc, 0, 0);
+    if( rc==SQLITE_OK && SQLITE_TXN_NONE==sqlite3BtreeTxnState(p->pSrc) ){
+      rc = sqlite3BtreeBeginTrans(p->pSrc, 0, 0);
       bCloseTrans = 1;
     }
 
+    /* Locate the destination btree and pager. */
+    if( (pDest = p->pDest)==0 ){
+      pDest = findBtree(p->pDestDb, p->pDestDb, p->zDestDb);
+    }
+    if( pDest==0 ){
+      rc = SQLITE_ERROR;
+    }else{
+      pDestPager = sqlite3BtreePager(pDest);
+    }
+
     /* If the destination database has not yet been locked (i.e. if this
     ** is the first call to backup_step() for the current backup operation),
     ** try to set its page size to the same as the source database. This
     ** is especially important on ZipVFS systems, as in that case it is
     ** not possible to create a database file that uses one page size by
     ** writing to it with another.  */
-    if( p->bDestLocked==0 && rc==SQLITE_OK && setDestPgsz(p)==SQLITE_NOMEM ){
+    if( p->bDestLocked==0 && rc==SQLITE_OK 
+     && setDestPgsz(pDest, p->pSrc)==SQLITE_NOMEM
+    ){
       rc = SQLITE_NOMEM;
     }
 
@@ -388,28 +391,30 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
                                                 (int*)&p->iDestSchema)) 
     ){
       p->bDestLocked = 1;
+      p->pDest = pDest;
     }
 
     /* Do not allow backup if the destination database is in WAL mode
     ** and the page sizes are different between source and destination */
-    pgszSrc = sqlite3BtreeGetPageSize(pSrc);
-    pgszDest = sqlite3BtreeGetPageSize(pDest);
-    destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(pDest));
-    if( SQLITE_OK==rc 
-     && (destMode==PAGER_JOURNALMODE_WAL || sqlite3PagerIsMemdb(pDestPager))
-     && pgszSrc!=pgszDest 
-    ){
-      rc = SQLITE_READONLY;
+    if( rc==SQLITE_OK ){
+      pgszSrc = sqlite3BtreeGetPageSize(p->pSrc);
+      pgszDest = sqlite3BtreeGetPageSize(p->pDest);
+      destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest));
+      if( (destMode==PAGER_JOURNALMODE_WAL || sqlite3PagerIsMemdb(pDestPager))
+        && pgszSrc!=pgszDest 
+      ){
+        rc = SQLITE_READONLY;
+      }
     }
   
     /* Now that there is a read-lock on the source database, query the
     ** source pager for the number of pages in the database.
     */
-    nSrcPage = (int)sqlite3BtreeLastPage(pSrc);
+    nSrcPage = (int)sqlite3BtreeLastPage(p->pSrc);
     assert( nSrcPage>=0 );
     for(ii=0; (nPage<0 || ii<nPage) && p->iNext<=(Pgno)nSrcPage && !rc; ii++){
       const Pgno iSrcPg = p->iNext;                 /* Source page number */
-      if( iSrcPg!=PENDING_BYTE_PAGE(pSrc->pBt) ){
+      if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){
         DbPage *pSrcPg;                             /* Source page object */
         rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg,PAGER_GET_READONLY);
         if( rc==SQLITE_OK ){
@@ -436,18 +441,18 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
     */
     if( rc==SQLITE_DONE ){
       if( nSrcPage==0 ){
-        rc = sqlite3BtreeNewDb(pDest);
+        rc = sqlite3BtreeNewDb(p->pDest);
         nSrcPage = 1;
       }
       if( rc==SQLITE_OK || rc==SQLITE_DONE ){
-        rc = sqlite3BtreeUpdateMeta(pDest,1,p->iDestSchema+1);
+        rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1);
       }
       if( rc==SQLITE_OK ){
         if( p->pDestDb ){
           sqlite3ResetAllSchemasOfConnection(p->pDestDb);
         }
         if( destMode==PAGER_JOURNALMODE_WAL ){
-          rc = sqlite3BtreeSetVersion(pDest, 2);
+          rc = sqlite3BtreeSetVersion(p->pDest, 2);
         }
       }
       if( rc==SQLITE_OK ){
@@ -464,12 +469,12 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
         ** journalled by PagerCommitPhaseOne() before they are destroyed
         ** by the file truncation.
         */
-        assert( pgszSrc==sqlite3BtreeGetPageSize(pSrc) );
-        assert( pgszDest==sqlite3BtreeGetPageSize(pDest) );
+        assert( pgszSrc==sqlite3BtreeGetPageSize(p->pSrc) );
+        assert( pgszDest==sqlite3BtreeGetPageSize(p->pDest) );
         if( pgszSrc<pgszDest ){
           int ratio = pgszDest/pgszSrc;
           nDestTruncate = (nSrcPage+ratio-1)/ratio;
-          if( nDestTruncate==(int)PENDING_BYTE_PAGE(pDest->pBt) ){
+          if( nDestTruncate==(int)PENDING_BYTE_PAGE(p->pDest->pBt) ){
             nDestTruncate--;
           }
         }else{
@@ -497,7 +502,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
           assert( pFile );
           assert( nDestTruncate==0 
               || (i64)nDestTruncate*(i64)pgszDest >= iSize || (
-                nDestTruncate==(int)(PENDING_BYTE_PAGE(pDest->pBt)-1)
+                nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
              && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
           ));
 
@@ -509,7 +514,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
           ** journal file.  */
           sqlite3PagerPagecount(pDestPager, &nDstPage);
           for(iPg=nDestTruncate; rc==SQLITE_OK && iPg<=(Pgno)nDstPage; iPg++){
-            if( iPg!=PENDING_BYTE_PAGE(pDest->pBt) ){
+            if( iPg!=PENDING_BYTE_PAGE(p->pDest->pBt) ){
               DbPage *pPg;
               rc = sqlite3PagerGet(pDestPager, iPg, &pPg, 0);
               if( rc==SQLITE_OK ){
@@ -553,7 +558,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
     
         /* Finish committing the transaction to the destination database. */
         if( SQLITE_OK==rc
-         && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(pDest, 0))
+         && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0))
         ){
           rc = SQLITE_DONE;
         }
@@ -567,8 +572,8 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
     */
     if( bCloseTrans ){
       TESTONLY( int rc2 );
-      TESTONLY( rc2  = ) sqlite3BtreeCommitPhaseOne(pSrc, 0);
-      TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(pSrc, 0);
+      TESTONLY( rc2  = ) sqlite3BtreeCommitPhaseOne(p->pSrc, 0);
+      TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc, 0);
       assert( rc2==SQLITE_OK );
     }
   
@@ -580,7 +585,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
   if( p->pDestDb ){
     sqlite3_mutex_leave(p->pDestDb->mutex);
   }
-  sqlite3BtreeLeave(pSrc);
+  sqlite3BtreeLeave(p->pSrc);
   sqlite3_mutex_leave(p->pSrcDb->mutex);
   return rc;
 }
@@ -592,24 +597,22 @@ int sqlite3_backup_finish(sqlite3_backup *p){
   sqlite3_backup **pp;                 /* Ptr to head of pagers backup list */
   sqlite3 *pSrcDb;                     /* Source database connection */
   int rc;                              /* Value to return */
-  Btree *pSrcBt = 0;
 
   /* Enter the mutexes */
   if( p==0 ) return SQLITE_OK;
-  pSrcBt = getSourceBtree(p);
   pSrcDb = p->pSrcDb;
   sqlite3_mutex_enter(pSrcDb->mutex);
-  sqlite3BtreeEnter(pSrcBt);
+  sqlite3BtreeEnter(p->pSrc);
   if( p->pDestDb ){
     sqlite3_mutex_enter(p->pDestDb->mutex);
   }
 
   /* Detach this backup from the source pager. */
   if( p->pDestDb ){
-    pSrcBt->nBackup--;
+    p->pSrc->nBackup--;
   }
   if( p->isAttached ){
-    pp = sqlite3PagerBackupPtr(sqlite3BtreePager(pSrcBt));
+    pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc));
     assert( pp!=0 );
     while( *pp!=p ){
       pp = &(*pp)->pNext;
@@ -619,7 +622,9 @@ int sqlite3_backup_finish(sqlite3_backup *p){
   }
 
   /* If a transaction is still open on the Btree, roll it back. */
-  sqlite3BtreeRollback(getDestBtree(p), SQLITE_OK, 0);
+  if( p->pDest ){
+    sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0);
+  }
 
   /* Set the error code of the destination database handle. */
   rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc;
@@ -629,7 +634,7 @@ int sqlite3_backup_finish(sqlite3_backup *p){
     /* Exit the mutexes and free the backup context structure. */
     sqlite3LeaveMutexAndCloseZombie(p->pDestDb);
   }
-  sqlite3BtreeLeave(pSrcBt);
+  sqlite3BtreeLeave(p->pSrc);
   if( p->pDestDb ){
     /* EVIDENCE-OF: R-64852-21591 The sqlite3_backup object is created by a
     ** call to sqlite3_backup_init() and is destroyed by a call to
@@ -687,7 +692,7 @@ static SQLITE_NOINLINE void backupUpdate(
 ){
   assert( p!=0 );
   do{
-    assert( sqlite3_mutex_held(getSourceBtree(p)->pBt->mutex) );
+    assert( sqlite3_mutex_held(p->pSrc->pBt->mutex) );
     if( !isFatalError(p->rc) && iPage<p->iNext ){
       /* The backup process p has already copied page iPage. But now it
       ** has been modified by a transaction on the source pager. Copy
@@ -723,7 +728,7 @@ void sqlite3BackupUpdate(sqlite3_backup *pBackup, Pgno iPage, const u8 *aData){
 void sqlite3BackupRestart(sqlite3_backup *pBackup){
   sqlite3_backup *p;                   /* Iterator variable */
   for(p=pBackup; p; p=p->pNext){
-    assert( sqlite3_mutex_held(getSourceBtree(p)->pBt->mutex) );
+    assert( sqlite3_mutex_held(p->pSrc->pBt->mutex) );
     p->iNext = 1;
   }
 }
@@ -737,12 +742,10 @@ void sqlite3BackupRestart(sqlite3_backup *pBackup){
 ** goes wrong, the transaction on pTo is rolled back. If successful, the 
 ** transaction is committed before returning.
 */
-int sqlite3BtreeCopyFile(sqlite3 *db, int iTo, int iFrom){
+int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
   int rc;
   sqlite3_file *pFd;              /* File descriptor for database pTo */
   sqlite3_backup b;
-  Btree *pFrom = db->aDb[iFrom].pBt;
-  Btree *pTo = db->aDb[iTo].pBt;
   sqlite3BtreeEnter(pTo);
   sqlite3BtreeEnter(pFrom);
 
@@ -761,9 +764,9 @@ int sqlite3BtreeCopyFile(sqlite3 *db, int iTo, int iFrom){
   ** from this function, not directly by the user.
   */
   memset(&b, 0, sizeof(b));
-  b.pSrcDb = db;
-  b.iSrc = iFrom;
-  b.iDest = iTo;
+  b.pSrcDb = pFrom->db;
+  b.pSrc = pFrom;
+  b.pDest = pTo;
   b.iNext = 1;
 
   /* 0x7FFFFFFF is the hard limit for the number of pages in a database
@@ -779,7 +782,7 @@ int sqlite3BtreeCopyFile(sqlite3 *db, int iTo, int iFrom){
   if( rc==SQLITE_OK ){
     pTo->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED;
   }else{
-    sqlite3PagerClearCache(sqlite3BtreePager(pTo));
+    sqlite3PagerClearCache(sqlite3BtreePager(b.pDest));
   }
 
   assert( sqlite3BtreeTxnState(pTo)!=SQLITE_TXN_WRITE );
index ba9a540eb681b9af6cac33fb9810f1b1497db3cd..043056e32b7ad9b8cb51e6bbd52ede7024d19102 100644 (file)
@@ -105,7 +105,7 @@ int sqlite3BtreeSavepoint(Btree *, int, int);
 
 const char *sqlite3BtreeGetFilename(Btree *);
 const char *sqlite3BtreeGetJournalname(Btree *);
-int sqlite3BtreeCopyFile(sqlite3*, int, int);
+int sqlite3BtreeCopyFile(Btree*, Btree*);
 
 int sqlite3BtreeIncrVacuum(Btree *);
 
index 7c6b818dbaed1a7861795d6b4ec2435bc383eacf..43b8be8683da2c0f5da55f42bce6e32562249c94 100644 (file)
@@ -608,6 +608,7 @@ void sqlite3CollapseDatabaseArray(sqlite3 *db){
     }
     if( j<i ){
       db->aDb[j] = db->aDb[i];
+//      sqlite3BackupUpdateSrc(db, j);
     }
     j++;
   }
index 94de364de718a71276b6d6cb09c12dfee9b70ddf..70e62e1ef1b71693a193e915a50dd19e31fc648c 100644 (file)
@@ -376,9 +376,7 @@ SQLITE_NOINLINE int sqlite3RunVacuum(
     }
 
     if( pOut==0 ){
-      assert( pMain==db->aDb[iDb].pBt );
-      assert( pTemp==db->aDb[nDb].pBt );
-      rc = sqlite3BtreeCopyFile(db, iDb, nDb);
+      rc = sqlite3BtreeCopyFile(pMain, pTemp);
     }
     if( rc!=SQLITE_OK ) goto end_of_vacuum;
     rc = sqlite3BtreeCommit(pTemp);
index e68a258c3d41db060f54e7ea8ead2a27f7b552fd..39092cc49436e46704c7c9df6361fff022406cd7 100644 (file)
@@ -65,7 +65,9 @@ do_test 1.7 {
 #-------------------------------------------------------------------------
 reset_db
 
-forcedelete test2.db
+foreach n {test2.db test3.db test4.db test5.db test6.db test7.db test8.db} {
+  forcedelete $n
+}
 
 do_execsql_test 2.0 {
   CREATE TABLE t1(a, b);
@@ -75,7 +77,7 @@ do_execsql_test 2.0 {
   INSERT INTO t2 VALUES(3, 3);
   CREATE INDEX i1 ON t1(a);
   CREATE INDEX i2 ON t2(a);
-  ATTACH 'test.db2' AS aux2;
+  ATTACH 'test2.db' AS aux2;
 }
 
 sqlite3 db2 test2.db
@@ -85,17 +87,48 @@ do_test 2.1 {
   B step 1
 
   execsql {
-    ATTACH 'test.db3' AS aux3;
-    ATTACH 'test.db4' AS aux4;
-    ATTACH 'test.db5' AS aux5;
-    ATTACH 'test.db6' AS aux6;
-    ATTACH 'test.db7' AS aux7;
-    ATTACH 'test.db8' AS aux8;
+    ATTACH 'test3.db' AS aux3;
+    ATTACH 'test4.db' AS aux4;
+    ATTACH 'test5.db' AS aux5;
+    ATTACH 'test6.db' AS aux6;
+    ATTACH 'test7.db' AS aux7;
+    ATTACH 'test8.db' AS aux8;
   }
 
   B step 200
   B finish
 } {SQLITE_OK}
 
+db2 close
+forcedelete test2.db
+
+do_execsql_test 2.2 {
+  CREATE TABLE aux7.t3(a, b);
+  CREATE TABLE aux7.t4(a, b);
+  INSERT INTO t4 VALUES(1, 1);
+  INSERT INTO t4 VALUES(2, 2);
+  INSERT INTO t4 VALUES(3, 3);
+  CREATE INDEX aux7.i3 ON t3(a);
+  CREATE INDEX aux7.i4 ON t4(a);
+}
+
+sqlite3 db2 test2.db
+
+do_test 2.3 {
+  sqlite3_backup B db2 main db aux7
+  B step 1
+
+  execsql {
+    DETACH aux4;
+  }
+
+  B step 200
+  B finish
+} {SQLITE_OK}
+
+do_test 2.4 {
+  sqlite3_backup B db2 main db aux7
+  B finish
+} {SQLITE_OK}
 
 finish_test