Esempio n. 1
0
        /*
        ** 2009 January 28
        **
        ** The author disclaims copyright to this source code.  In place of
        ** a legal notice, here is a blessing:
        **
        **    May you do good and not evil.
        **    May you find forgiveness for yourself and forgive others.
        **    May you share freely, never taking more than you give.
        **
        *************************************************************************
        ** This file contains the implementation of the sqlite3_backup_XXX()
        ** API functions and the related features.
        *************************************************************************
        **  Included in SQLite3 port to C#-SQLite;  2008 Noah B Hart
        **  C#-SQLite is an independent reimplementation of the SQLite software library
        **
        **  SQLITE_SOURCE_ID: 2011-01-28 17:03:50 ed759d5a9edb3bba5f48f243df47be29e3fe8cd7
        **
        *************************************************************************
        */
        //#include "sqliteInt.h"
        //#include "btreeInt.h"
        /* Macro to find the minimum of two numeric values.
        */
        //# define MIN(x,y) ((x)<(y)?(x):(y))

        #endif

        #region Methods

        /*
        ** Release all resources associated with an sqlite3_backup* handle.
        */
        public static int sqlite3_backup_finish( sqlite3_backup p )
        {
            sqlite3_backup pp;                 /* Ptr to head of pagers backup list */
              sqlite3_mutex mutex;               /* Mutex to protect source database */
              int rc;                            /* Value to return */

              /* Enter the mutexes */
              if ( p == null )
            return SQLITE_OK;
              sqlite3_mutex_enter( p.pSrcDb.mutex );
              sqlite3BtreeEnter( p.pSrc );
              mutex = p.pSrcDb.mutex;
              if ( p.pDestDb != null )
              {
            sqlite3_mutex_enter( p.pDestDb.mutex );
              }

              /* Detach this backup from the source pager. */
              if ( p.pDestDb != null )
              {
            p.pSrc.nBackup--;
              }
              if ( p.isAttached != 0 )
              {
            pp = sqlite3PagerBackupPtr( sqlite3BtreePager( p.pSrc ) );
            while ( pp != p )
            {
              pp = ( pp ).pNext;
            }
            sqlite3BtreePager( p.pSrc ).pBackup = p.pNext;
              }

              /* If a transaction is still open on the Btree, roll it back. */
              sqlite3BtreeRollback( p.pDest );

              /* Set the error code of the destination database handle. */
              rc = ( p.rc == SQLITE_DONE ) ? SQLITE_OK : p.rc;
              sqlite3Error( p.pDestDb, rc, 0 );

              /* Exit the mutexes and free the backup context structure. */
              if ( p.pDestDb != null )
              {
            sqlite3_mutex_leave( p.pDestDb.mutex );
              }
              sqlite3BtreeLeave( p.pSrc );
              if ( p.pDestDb != null )
              {
            /* 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(). */
            //sqlite3_free( ref p );
              }
              sqlite3_mutex_leave( mutex );
              return rc;
        }
        static int backupTestCmd(
            ClientData clientData,
            Tcl_Interp interp,
            int objc,
            Tcl_Obj[] objv
            )
        {
            BackupSubCommand[] aSub = new BackupSubCommand[] {
                new BackupSubCommand("step", BackupSubCommandEnum.BACKUP_STEP, 1, "npage"),
                new BackupSubCommand("finish", BackupSubCommandEnum.BACKUP_FINISH, 0, ""),
                new BackupSubCommand("remaining", BackupSubCommandEnum.BACKUP_REMAINING, 0, ""),
                new BackupSubCommand("pagecount", BackupSubCommandEnum.BACKUP_PAGECOUNT, 0, ""),
                new BackupSubCommand(null, 0, 0, null)
            };

            sqlite3_backup p    = (sqlite3_backup)clientData;
            int            iCmd = 0;
            int            rc;

            rc = Tcl_GetIndexFromObjStruct(
                interp, objv[1], aSub, aSub.Length, "option", 0, ref iCmd
                );
            if (rc != TCL.TCL_OK)
            {
                return(rc);
            }
            if (objc != (2 + aSub[iCmd].nArg))
            {
                TCL.Tcl_WrongNumArgs(interp, 2, objv, aSub[iCmd].zArg);
                return(TCL.TCL_ERROR);
            }

            switch (aSub[iCmd].eCmd)
            {
            case BackupSubCommandEnum.BACKUP_FINISH:
            {
                string         zCmdName;
                WrappedCommand cmdInfo = null;
                zCmdName = TCL.Tcl_GetString(objv[0]);
                TCL.Tcl_GetCommandInfo(interp, zCmdName, ref cmdInfo);
                cmdInfo.deleteProc = null;
                TCL.Tcl_SetCommandInfo(interp, zCmdName, cmdInfo);
                TCL.Tcl_DeleteCommand(interp, zCmdName);

                rc = sqlite3_backup_finish(p);
                TCL.Tcl_SetResult(interp, sqlite3TestErrorName(rc), TCL.TCL_STATIC);
                break;
            }

            case BackupSubCommandEnum.BACKUP_STEP:
            {
                int nPage = 0;
                if (TCL.Tcl_GetIntFromObj(interp, objv[2], ref nPage))
                {
                    return(TCL.TCL_ERROR);
                }
                rc = sqlite3_backup_step(p, nPage);
                TCL.Tcl_SetResult(interp, sqlite3TestErrorName(rc), TCL.TCL_STATIC);
                break;
            }

            case BackupSubCommandEnum.BACKUP_REMAINING:
                TCL.Tcl_SetObjResult(interp, TCL.Tcl_NewIntObj(sqlite3_backup_remaining(p)));
                break;

            case BackupSubCommandEnum.BACKUP_PAGECOUNT:
                TCL.Tcl_SetObjResult(interp, TCL.Tcl_NewIntObj(sqlite3_backup_pagecount(p)));
                break;
            }

            return(TCL.TCL_OK);
        }
Esempio n. 3
0
/*
** Copy nPage pages from the source b-tree to the destination.
*/
        static public int sqlite3_backup_step(sqlite3_backup p, int nPage)
        {
            int rc;
            int destMode;     /* Destination journal mode */
            int pgszSrc  = 0; /* Source page size */
            int pgszDest = 0; /* Destination page size */

            sqlite3_mutex_enter(p.pSrcDb.mutex);
            sqlite3BtreeEnter(p.pSrc);
            if (p.pDestDb != null)
            {
                sqlite3_mutex_enter(p.pDestDb.mutex);
            }

            rc = p.rc;
            if (!isFatalError(rc))
            {
                Pager pSrcPager  = sqlite3BtreePager(p.pSrc);  /* Source pager */
                Pager pDestPager = sqlite3BtreePager(p.pDest); /* Dest pager */
                int   ii;                                      /* Iterator variable */
                Pgno  nSrcPage    = 0;                         /* Size of source db in pages */
                int   bCloseTrans = 0;                         /* True if src db requires unlocking */

                /* If the source pager is currently in a write-transaction, return
                ** SQLITE_BUSY immediately.
                */
                if (p.pDestDb != null && p.pSrc.pBt.inTransaction == TRANS_WRITE)
                {
                    rc = SQLITE_BUSY;
                }
                else
                {
                    rc = SQLITE_OK;
                }

                /* Lock the destination database, if it is not locked already. */
                if (SQLITE_OK == rc && p.bDestLocked == 0 &&
                    SQLITE_OK == (rc = sqlite3BtreeBeginTrans(p.pDest, 2))
                    )
                {
                    p.bDestLocked = 1;
                    sqlite3BtreeGetMeta(p.pDest, BTREE_SCHEMA_VERSION, ref p.iDestSchema);
                }

                /* 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 && !sqlite3BtreeIsInReadTrans(p.pSrc))
                {
                    rc          = sqlite3BtreeBeginTrans(p.pSrc, 0);
                    bCloseTrans = 1;
                }

                /* Do not allow backup if the destination database is in WAL mode
                ** and the page sizes are different between source and destination */
                pgszSrc  = sqlite3BtreeGetPageSize(p.pSrc);
                pgszDest = sqlite3BtreeGetPageSize(p.pDest);
                destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p.pDest));
                if (SQLITE_OK == rc && destMode == PAGER_JOURNALMODE_WAL && 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 = sqlite3BtreeLastPage(p.pSrc);
                Debug.Assert(nSrcPage >= 0);

                for (ii = 0; (nPage < 0 || ii < nPage) && p.iNext <= nSrcPage && 0 == rc; ii++)
                {
                    Pgno iSrcPg = p.iNext;   /* Source page number */
                    if (iSrcPg != PENDING_BYTE_PAGE(p.pSrc.pBt))
                    {
                        DbPage pSrcPg = null;             /* Source page object */
                        rc = sqlite3PagerGet(pSrcPager, (u32)iSrcPg, ref pSrcPg);
                        if (rc == SQLITE_OK)
                        {
                            rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg));
                            sqlite3PagerUnref(pSrcPg);
                        }
                    }
                    p.iNext++;
                }
                if (rc == SQLITE_OK)
                {
                    p.nPagecount = nSrcPage;
                    p.nRemaining = (nSrcPage + 1 - p.iNext);
                    if (p.iNext > nSrcPage)
                    {
                        rc = SQLITE_DONE;
                    }
                    else if (0 == p.isAttached)
                    {
                        attachBackupObject(p);
                    }
                }


                /* Update the schema version field in the destination database. This
                ** is to make sure that the schema-version really does change in
                ** the case where the source and destination databases have the
                ** same schema version.
                */
                if (rc == SQLITE_DONE &&
                    (rc = sqlite3BtreeUpdateMeta(p.pDest, 1, p.iDestSchema + 1)) == SQLITE_OK
                    )
                {
                    Pgno nDestTruncate;
                    if (p.pDestDb != null)
                    {
                        sqlite3ResetInternalSchema(p.pDestDb, -1);
                    }

                    /* Set nDestTruncate to the final number of pages in the destination
                    ** database. The complication here is that the destination page
                    ** size may be different to the source page size.
                    **
                    ** If the source page size is smaller than the destination page size,
                    ** round up. In this case the call to sqlite3OsTruncate() below will
                    ** fix the size of the file. However it is important to call
                    ** 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.
                    */
                    Debug.Assert(pgszSrc == sqlite3BtreeGetPageSize(p.pSrc));
                    Debug.Assert(pgszDest == sqlite3BtreeGetPageSize(p.pDest));
                    if (pgszSrc < pgszDest)
                    {
                        int ratio = pgszDest / pgszSrc;
                        nDestTruncate = (Pgno)((nSrcPage + ratio - 1) / ratio);
                        if (nDestTruncate == (int)PENDING_BYTE_PAGE(p.pDest.pBt))
                        {
                            nDestTruncate--;
                        }
                    }
                    else
                    {
                        nDestTruncate = (Pgno)(nSrcPage * (pgszSrc / pgszDest));
                    }
                    sqlite3PagerTruncateImage(pDestPager, nDestTruncate);

                    if (pgszSrc < pgszDest)
                    {
                        /* If the source page-size is smaller than the destination page-size,
                        ** two extra things may need to happen:
                        **
                        **   * The destination may need to be truncated, and
                        **
                        **   * Data stored on the pages immediately following the
                        **     pending-byte page in the source database may need to be
                        **     copied into the destination database.
                        */
                        int          iSize = (int)(pgszSrc * nSrcPage);
                        sqlite3_file pFile = sqlite3PagerFile(pDestPager);
                        i64          iOff;
                        i64          iEnd;

                        Debug.Assert(pFile != null);
                        Debug.Assert((i64)nDestTruncate * (i64)pgszDest >= iSize || (
                                         nDestTruncate == (int)(PENDING_BYTE_PAGE(p.pDest.pBt) - 1) &&
                                         iSize >= PENDING_BYTE && iSize <= PENDING_BYTE + pgszDest
                                         ));

                        /* This call ensures that all data required to recreate the original
                        ** database has been stored in the journal for pDestPager and the
                        ** journal synced to disk. So at this point we may safely modify
                        ** the database file in any way, knowing that if a power failure
                        ** occurs, the original database will be reconstructed from the
                        ** journal file.  */
                        rc = sqlite3PagerCommitPhaseOne(pDestPager, null, true);

                        /* Write the extra pages and truncate the database file as required. */
                        iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
                        for (
                            iOff = PENDING_BYTE + pgszSrc;
                            rc == SQLITE_OK && iOff < iEnd;
                            iOff += pgszSrc
                            )
                        {
                            PgHdr pSrcPg = null;
                            u32   iSrcPg = (u32)((iOff / pgszSrc) + 1);
                            rc = sqlite3PagerGet(pSrcPager, iSrcPg, ref pSrcPg);
                            if (rc == SQLITE_OK)
                            {
                                byte[] zData = sqlite3PagerGetData(pSrcPg);
                                rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
                            }
                            sqlite3PagerUnref(pSrcPg);
                        }
                        if (rc == SQLITE_OK)
                        {
                            rc = backupTruncateFile(pFile, (int)iSize);
                        }

                        /* Sync the database file to disk. */
                        if (rc == SQLITE_OK)
                        {
                            rc = sqlite3PagerSync(pDestPager);
                        }
                    }
                    else
                    {
                        rc = sqlite3PagerCommitPhaseOne(pDestPager, null, false);
                    }

                    /* Finish committing the transaction to the destination database. */
                    if (SQLITE_OK == rc &&
                        SQLITE_OK == (rc = sqlite3BtreeCommitPhaseTwo(p.pDest, 0))
                        )
                    {
                        rc = SQLITE_DONE;
                    }
                }

                /* If bCloseTrans is true, then this function opened a read transaction
                ** on the source database. Close the read transaction here. There is
                ** no need to check the return values of the btree methods here, as
                ** "committing" a read-only transaction cannot fail.
                */
                if (bCloseTrans != 0)
                {
#if !NDEBUG || SQLITE_COVERAGE_TEST
                    //TESTONLY( int rc2 );
                    //TESTONLY( rc2  = ) sqlite3BtreeCommitPhaseOne(p.pSrc, 0);
                    //TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p.pSrc);
                    int rc2;
                    rc2  = sqlite3BtreeCommitPhaseOne(p.pSrc, "");
                    rc2 |= sqlite3BtreeCommitPhaseTwo(p.pSrc, 0);
                    Debug.Assert(rc2 == SQLITE_OK);
#else
                    sqlite3BtreeCommitPhaseOne(p.pSrc, null);
                    sqlite3BtreeCommitPhaseTwo(p.pSrc, 0);
#endif
                }

                if (rc == SQLITE_IOERR_NOMEM)
                {
                    rc = SQLITE_NOMEM;
                }
                p.rc = rc;
            }
            if (p.pDestDb != null)
            {
                sqlite3_mutex_leave(p.pDestDb.mutex);
            }
            sqlite3BtreeLeave(p.pSrc);
            sqlite3_mutex_leave(p.pSrcDb.mutex);
            return(rc);
        }
Esempio n. 4
0
 /*
 ** Return the total number of pages in the source database as of the most
 ** recent call to sqlite3_backup_step().
 */
 static int sqlite3_backup_pagecount( sqlite3_backup p )
 {
   return (int)p.nPagecount;
 }
Esempio n. 5
0
 /*
 ** Restart the backup process. This is called when the pager layer
 ** detects that the database has been modified by an external database
 ** connection. In this case there is no way of knowing which of the
 ** pages that have been copied into the destination database are still
 ** valid and which are not, so the entire process needs to be restarted.
 **
 ** It is assumed that the mutex associated with the BtShared object
 ** corresponding to the source database is held when this function is
 ** called.
 */
 static void sqlite3BackupRestart( sqlite3_backup pBackup )
 {
   sqlite3_backup p;                   /* Iterator variable */
   for ( p = pBackup; p != null; p = p.pNext )
   {
     Debug.Assert( sqlite3_mutex_held( p.pSrc.pBt.mutex ) );
     p.iNext = 1;
   }
 }
Esempio n. 6
0
    /*
    ** Parameter zSrcData points to a buffer containing the data for
    ** page iSrcPg from the source database. Copy this data into the
    ** destination database.
    */
    static int backupOnePage( sqlite3_backup p, Pgno iSrcPg, byte[] zSrcData )
    {
      Pager pDestPager = sqlite3BtreePager( p.pDest );
      int nSrcPgsz = sqlite3BtreeGetPageSize( p.pSrc );
      int nDestPgsz = sqlite3BtreeGetPageSize( p.pDest );
      int nCopy = MIN( nSrcPgsz, nDestPgsz );
      i64 iEnd = (i64)iSrcPg * (i64)nSrcPgsz;

      int rc = SQLITE_OK;
      i64 iOff;

      Debug.Assert( p.bDestLocked != 0 );
      Debug.Assert( !isFatalError( p.rc ) );
      Debug.Assert( iSrcPg != PENDING_BYTE_PAGE( p.pSrc.pBt ) );
      Debug.Assert( zSrcData != null );

      /* 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( pDestPager ) )
      {
        rc = SQLITE_READONLY;
      }

#if SQLITE_HAS_CODEC
      /* Backup is not possible if the page size of the destination is changing
** a a codec is in use.
*/
      if ( nSrcPgsz != nDestPgsz && sqlite3PagerGetCodec( pDestPager ) != null )
      {
        rc = SQLITE_READONLY;
      }
#endif

      /* This loop runs once for each destination page spanned by the source
** page. For each iteration, variable iOff is set to the byte offset
** of the destination page.
*/
      for ( iOff = iEnd - (i64)nSrcPgsz; rc == SQLITE_OK && iOff < iEnd; iOff += nDestPgsz )
      {
        DbPage pDestPg = null;
        u32 iDest = (u32)( iOff / nDestPgsz ) + 1;
        if ( iDest == PENDING_BYTE_PAGE( p.pDest.pBt ) )
          continue;
        if ( SQLITE_OK == ( rc = sqlite3PagerGet( pDestPager, iDest, ref pDestPg ) )
        && SQLITE_OK == ( rc = sqlite3PagerWrite( pDestPg ) )
        )
        {
          //string zIn = &zSrcData[iOff%nSrcPgsz];
          byte[] zDestData = sqlite3PagerGetData( pDestPg );
          //string zOut = &zDestData[iOff % nDestPgsz];

          /* Copy the data from the source page into the destination page.
          ** Then clear the Btree layer MemPage.isInit flag. Both this module
          ** and the pager code use this trick (clearing the first byte
          ** of the page 'extra' space to invalidate the Btree layers
          ** cached parse of the page). MemPage.isInit is marked
          ** "MUST BE FIRST" for this purpose.
          */
          Buffer.BlockCopy( zSrcData, (int)( iOff % nSrcPgsz ), zDestData, (int)( iOff % nDestPgsz ), nCopy );// memcpy( zOut, zIn, nCopy );
          sqlite3PagerGetExtra( pDestPg ).isInit = 0;// ( sqlite3PagerGetExtra( pDestPg ) )[0] = 0;
        }
        sqlite3PagerUnref( pDestPg );
      }

      return rc;
    }
Esempio n. 7
0
    /*
    ** Copy nPage pages from the source b-tree to the destination.
    */
    static public int sqlite3_backup_step( sqlite3_backup p, int nPage )
    {
      int rc;
      int destMode;       /* Destination journal mode */
      int pgszSrc = 0;    /* Source page size */
      int pgszDest = 0;   /* Destination page size */

      sqlite3_mutex_enter( p.pSrcDb.mutex );
      sqlite3BtreeEnter( p.pSrc );
      if ( p.pDestDb != null )
      {
        sqlite3_mutex_enter( p.pDestDb.mutex );
      }

      rc = p.rc;
      if ( !isFatalError( rc ) )
      {
        Pager pSrcPager = sqlite3BtreePager( p.pSrc );    /* Source pager */
        Pager pDestPager = sqlite3BtreePager( p.pDest );   /* Dest pager */
        int ii;                            /* Iterator variable */
        Pgno nSrcPage = 0;                 /* Size of source db in pages */
        int bCloseTrans = 0;               /* True if src db requires unlocking */

        /* If the source pager is currently in a write-transaction, return
        ** SQLITE_BUSY immediately.
        */
        if ( p.pDestDb != null && p.pSrc.pBt.inTransaction == TRANS_WRITE )
        {
          rc = SQLITE_BUSY;
        }
        else
        {
          rc = SQLITE_OK;
        }

        /* Lock the destination database, if it is not locked already. */
        if ( SQLITE_OK == rc && p.bDestLocked == 0
        && SQLITE_OK == ( rc = sqlite3BtreeBeginTrans( p.pDest, 2 ) )
        )
        {
          p.bDestLocked = 1;
          sqlite3BtreeGetMeta( p.pDest, BTREE_SCHEMA_VERSION, ref p.iDestSchema );
        }

        /* 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 && !sqlite3BtreeIsInReadTrans( p.pSrc ) )
        {
          rc = sqlite3BtreeBeginTrans( p.pSrc, 0 );
          bCloseTrans = 1;
        }

        /* Do not allow backup if the destination database is in WAL mode
        ** and the page sizes are different between source and destination */
        pgszSrc = sqlite3BtreeGetPageSize( p.pSrc );
        pgszDest = sqlite3BtreeGetPageSize( p.pDest );
        destMode = sqlite3PagerGetJournalMode( sqlite3BtreePager( p.pDest ) );
        if ( SQLITE_OK == rc && destMode == PAGER_JOURNALMODE_WAL && 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 = sqlite3BtreeLastPage( p.pSrc );
        Debug.Assert( nSrcPage >= 0 );

        for ( ii = 0; ( nPage < 0 || ii < nPage ) && p.iNext <= nSrcPage && 0 == rc; ii++ )
        {
          Pgno iSrcPg = p.iNext;                 /* Source page number */
          if ( iSrcPg != PENDING_BYTE_PAGE( p.pSrc.pBt ) )
          {
            DbPage pSrcPg = null;                             /* Source page object */
            rc = sqlite3PagerGet( pSrcPager, (u32)iSrcPg, ref pSrcPg );
            if ( rc == SQLITE_OK )
            {
              rc = backupOnePage( p, iSrcPg, sqlite3PagerGetData( pSrcPg ) );
              sqlite3PagerUnref( pSrcPg );
            }
          }
          p.iNext++;
        }
        if ( rc == SQLITE_OK )
        {
          p.nPagecount = nSrcPage;
          p.nRemaining = ( nSrcPage + 1 - p.iNext );
          if ( p.iNext > nSrcPage )
          {
            rc = SQLITE_DONE;
          }
          else if ( 0 == p.isAttached )
          {
            attachBackupObject( p );
          }
        }


        /* Update the schema version field in the destination database. This
        ** is to make sure that the schema-version really does change in
        ** the case where the source and destination databases have the
        ** same schema version.
        */
        if ( rc == SQLITE_DONE
        && ( rc = sqlite3BtreeUpdateMeta( p.pDest, 1, p.iDestSchema + 1 ) ) == SQLITE_OK
        )
        {
          Pgno nDestTruncate;
          if ( p.pDestDb != null )
          {
            sqlite3ResetInternalSchema( p.pDestDb, 0 );
          }

          /* Set nDestTruncate to the final number of pages in the destination
          ** database. The complication here is that the destination page
          ** size may be different to the source page size.
          **
          ** If the source page size is smaller than the destination page size,
          ** round up. In this case the call to sqlite3OsTruncate() below will
          ** fix the size of the file. However it is important to call
          ** 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.
          */
          Debug.Assert( pgszSrc == sqlite3BtreeGetPageSize( p.pSrc ) );
          Debug.Assert( pgszDest == sqlite3BtreeGetPageSize( p.pDest ) );
          if ( pgszSrc < pgszDest )
          {
            int ratio = pgszDest / pgszSrc;
            nDestTruncate = (Pgno)( ( nSrcPage + ratio - 1 ) / ratio );
            if ( nDestTruncate == (int)PENDING_BYTE_PAGE( p.pDest.pBt ) )
            {
              nDestTruncate--;
            }
          }
          else
          {
            nDestTruncate = (Pgno)( nSrcPage * ( pgszSrc / pgszDest ) );
          }
          sqlite3PagerTruncateImage( pDestPager, nDestTruncate );

          if ( pgszSrc < pgszDest )
          {
            /* If the source page-size is smaller than the destination page-size,
            ** two extra things may need to happen:
            **
            **   * The destination may need to be truncated, and
            **
            **   * Data stored on the pages immediately following the
            **     pending-byte page in the source database may need to be
            **     copied into the destination database.
            */
            int iSize = (int)( pgszSrc * nSrcPage );
            sqlite3_file pFile = sqlite3PagerFile( pDestPager );
            i64 iOff;
            i64 iEnd;

            Debug.Assert( pFile != null );
            Debug.Assert( (i64)nDestTruncate * (i64)pgszDest >= iSize || (
            nDestTruncate == (int)( PENDING_BYTE_PAGE( p.pDest.pBt ) - 1 )
            && iSize >= PENDING_BYTE && iSize <= PENDING_BYTE + pgszDest
            ) );

            /* This call ensures that all data required to recreate the original
            ** database has been stored in the journal for pDestPager and the
            ** journal synced to disk. So at this point we may safely modify
            ** the database file in any way, knowing that if a power failure
            ** occurs, the original database will be reconstructed from the 
            ** journal file.  */
            rc = sqlite3PagerCommitPhaseOne( pDestPager, null, true );

            /* Write the extra pages and truncate the database file as required. */
            iEnd = MIN( PENDING_BYTE + pgszDest, iSize );
            for (
            iOff = PENDING_BYTE + pgszSrc;
            rc == SQLITE_OK && iOff < iEnd;
            iOff += pgszSrc
            )
            {
              PgHdr pSrcPg = null;
              u32 iSrcPg = (u32)( ( iOff / pgszSrc ) + 1 );
              rc = sqlite3PagerGet( pSrcPager, iSrcPg, ref pSrcPg );
              if ( rc == SQLITE_OK )
              {
                byte[] zData = sqlite3PagerGetData( pSrcPg );
                rc = sqlite3OsWrite( pFile, zData, pgszSrc, iOff );
              }
              sqlite3PagerUnref( pSrcPg );
            }
            if ( rc == SQLITE_OK )
            {
              rc = backupTruncateFile( pFile, (int)iSize );
            }

            /* Sync the database file to disk. */
            if ( rc == SQLITE_OK )
            {
              rc = sqlite3PagerSync( pDestPager );
            }
          }
          else
          {
            rc = sqlite3PagerCommitPhaseOne( pDestPager, null, false );
          }

          /* Finish committing the transaction to the destination database. */
          if ( SQLITE_OK == rc
          && SQLITE_OK == ( rc = sqlite3BtreeCommitPhaseTwo( p.pDest ) )
          )
          {
            rc = SQLITE_DONE;
          }
        }

        /* If bCloseTrans is true, then this function opened a read transaction
        ** on the source database. Close the read transaction here. There is
        ** no need to check the return values of the btree methods here, as
        ** "committing" a read-only transaction cannot fail.
        */
        if ( bCloseTrans != 0 )
        {
#if !NDEBUG || SQLITE_COVERAGE_TEST
          //TESTONLY( int rc2 );
          //TESTONLY( rc2  = ) sqlite3BtreeCommitPhaseOne(p.pSrc, 0);
          //TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p.pSrc);
          int rc2;
          rc2 = sqlite3BtreeCommitPhaseOne( p.pSrc, "" );
          rc2 |= sqlite3BtreeCommitPhaseTwo( p.pSrc );
          Debug.Assert( rc2 == SQLITE_OK );
#else
sqlite3BtreeCommitPhaseOne(p.pSrc, null);
sqlite3BtreeCommitPhaseTwo(p.pSrc);
#endif
        }

        if ( rc == SQLITE_IOERR_NOMEM )
        {
          rc = SQLITE_NOMEM;
        }
        p.rc = rc;
      }
      if ( p.pDestDb != null )
      {
        sqlite3_mutex_leave( p.pDestDb.mutex );
      }
      sqlite3BtreeLeave( p.pSrc );
      sqlite3_mutex_leave( p.pSrcDb.mutex );
      return rc;
    }
Esempio n. 8
0
        /*
        ** Copy nPage pages from the source b-tree to the destination.
        */
        public static int sqlite3_backup_step(sqlite3_backup p, int nPage)
        {
            int rc;

            sqlite3_mutex_enter(p.pSrcDb.mutex);
            sqlite3BtreeEnter(p.pSrc);
            if (p.pDestDb != null)
            {
                sqlite3_mutex_enter(p.pDestDb.mutex);
            }

            rc = p.rc;
            if (!isFatalError(rc))
            {
                var  pSrcPager  = sqlite3BtreePager(p.pSrc);  /* Source pager */
                var  pDestPager = sqlite3BtreePager(p.pDest); /* Dest pager */
                int  ii;                                      /* Iterator variable */
                uint nSrcPage    = 0;                         /* Size of source db in pages */
                var  bCloseTrans = 0;                         /* True if src db requires unlocking */

                /* If the source pager is currently in a write-transaction, return
                ** SQLITE_BUSY immediately.
                */
                if (p.pDestDb != null && p.pSrc.pBt.inTransaction == TRANS_WRITE)
                {
                    rc = SQLITE_BUSY;
                }
                else
                {
                    rc = SQLITE_OK;
                }

                /* Lock the destination database, if it is not locked already. */
                if (SQLITE_OK == rc && p.bDestLocked == 0 &&
                    SQLITE_OK == (rc = sqlite3BtreeBeginTrans(p.pDest, 2))
                    )
                {
                    p.bDestLocked = 1;
                    sqlite3BtreeGetMeta(p.pDest, BTREE_SCHEMA_VERSION, ref p.iDestSchema);
                }

                /* 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 && !sqlite3BtreeIsInReadTrans(p.pSrc))
                {
                    rc          = sqlite3BtreeBeginTrans(p.pSrc, 0);
                    bCloseTrans = 1;
                }

                /* Now that there is a read-lock on the source database, query the
                ** source pager for the number of pages in the database.
                */
                if (rc == SQLITE_OK)
                {
                    rc = sqlite3PagerPagecount(pSrcPager, ref nSrcPage);
                }
                for (ii = 0; (nPage < 0 || ii < nPage) && p.iNext <= nSrcPage && 0 == rc; ii++)
                {
                    var iSrcPg = p.iNext; /* Source page number */
                    if (iSrcPg != PENDING_BYTE_PAGE(p.pSrc.pBt))
                    {
                        DbPage pSrcPg = null; /* Source page object */
                        rc = sqlite3PagerGet(pSrcPager, iSrcPg, ref pSrcPg);
                        if (rc == SQLITE_OK)
                        {
                            rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg));
                            sqlite3PagerUnref(pSrcPg);
                        }
                    }

                    p.iNext++;
                }

                if (rc == SQLITE_OK)
                {
                    p.nPagecount = nSrcPage;
                    p.nRemaining = nSrcPage + 1 - p.iNext;
                    if (p.iNext > nSrcPage)
                    {
                        rc = SQLITE_DONE;
                    }
                    else if (0 == p.isAttached)
                    {
                        attachBackupObject(p);
                    }
                }


                /* Update the schema version field in the destination database. This
                ** is to make sure that the schema-version really does change in
                ** the case where the source and destination databases have the
                ** same schema version.
                */
                if (rc == SQLITE_DONE &&
                    (rc = sqlite3BtreeUpdateMeta(p.pDest, 1, p.iDestSchema + 1)) == SQLITE_OK
                    )
                {
                    var  nSrcPagesize  = sqlite3BtreeGetPageSize(p.pSrc);
                    var  nDestPagesize = sqlite3BtreeGetPageSize(p.pDest);
                    uint nDestTruncate;
                    if (p.pDestDb != null)
                    {
                        sqlite3ResetInternalSchema(p.pDestDb, 0);
                    }

                    /* Set nDestTruncate to the final number of pages in the destination
                    ** database. The complication here is that the destination page
                    ** size may be different to the source page size.
                    **
                    ** If the source page size is smaller than the destination page size,
                    ** round up. In this case the call to sqlite3OsTruncate() below will
                    ** fix the size of the file. However it is important to call
                    ** 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 (nSrcPagesize < nDestPagesize)
                    {
                        var ratio = nDestPagesize / nSrcPagesize;
                        nDestTruncate = (uint)((nSrcPage + ratio - 1) / ratio);
                        if (nDestTruncate == (int)PENDING_BYTE_PAGE(p.pDest.pBt))
                        {
                            nDestTruncate--;
                        }
                    }
                    else
                    {
                        nDestTruncate = (uint)(nSrcPage * (nSrcPagesize / nDestPagesize));
                    }

                    sqlite3PagerTruncateImage(pDestPager, nDestTruncate);

                    if (nSrcPagesize < nDestPagesize)
                    {
                        /* If the source page-size is smaller than the destination page-size,
                        ** two extra things may need to happen:
                        **
                        **   * The destination may need to be truncated, and
                        **
                        **   * Data stored on the pages immediately following the
                        **     pending-byte page in the source database may need to be
                        **     copied into the destination database.
                        */
                        var iSize = (uint)nSrcPagesize * nSrcPage;
                        var pFile = sqlite3PagerFile(pDestPager);

                        Debug.Assert(pFile != null);
                        Debug.Assert(nDestTruncate * nDestPagesize >= iSize ||
                                     nDestTruncate == (int)(PENDING_BYTE_PAGE(p.pDest.pBt) - 1) &&
                                     iSize >= PENDING_BYTE && iSize <= PENDING_BYTE + nDestPagesize);
                        if (SQLITE_OK == (rc = sqlite3PagerCommitPhaseOne(pDestPager, null, true)) &&
                            SQLITE_OK == (rc = backupTruncateFile(pFile, (int)iSize)) &&
                            SQLITE_OK == (rc = sqlite3PagerSync(pDestPager))
                            )
                        {
                            long iOff;
                            long iEnd = MIN(PENDING_BYTE + nDestPagesize, iSize);
                            for (
                                iOff = PENDING_BYTE + nSrcPagesize;
                                rc == SQLITE_OK && iOff < iEnd;
                                iOff += nSrcPagesize
                                )
                            {
                                PgHdr pSrcPg = null;
                                var   iSrcPg = (uint)(iOff / nSrcPagesize + 1);
                                rc = sqlite3PagerGet(pSrcPager, iSrcPg, ref pSrcPg);
                                if (rc == SQLITE_OK)
                                {
                                    var zData = sqlite3PagerGetData(pSrcPg);
                                    rc = sqlite3OsWrite(pFile, zData, nSrcPagesize, iOff);
                                }

                                sqlite3PagerUnref(pSrcPg);
                            }
                        }
                    }
                    else
                    {
                        rc = sqlite3PagerCommitPhaseOne(pDestPager, null, false);
                    }

                    /* Finish committing the transaction to the destination database. */
                    if (SQLITE_OK == rc &&
                        SQLITE_OK == (rc = sqlite3BtreeCommitPhaseTwo(p.pDest))
                        )
                    {
                        rc = SQLITE_DONE;
                    }
                }

                /* If bCloseTrans is true, then this function opened a read transaction
                ** on the source database. Close the read transaction here. There is
                ** no need to check the return values of the btree methods here, as
                ** "committing" a read-only transaction cannot fail.
                */
                if (bCloseTrans != 0)
                {
#if !NDEBUG || SQLITE_COVERAGE_TEST
                    //TESTONLY( int rc2 );
                    //TESTONLY( rc2  = ) sqlite3BtreeCommitPhaseOne(p.pSrc, 0);
                    //TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p.pSrc);
                    int rc2;
                    rc2  = sqlite3BtreeCommitPhaseOne(p.pSrc, "");
                    rc2 |= sqlite3BtreeCommitPhaseTwo(p.pSrc);
                    Debug.Assert(rc2 == SQLITE_OK);
#else
                    sqlite3BtreeCommitPhaseOne(p.pSrc, null);
                    sqlite3BtreeCommitPhaseTwo(p.pSrc);
#endif
                }

                p.rc = rc;
            }

            if (p.pDestDb != null)
            {
                sqlite3_mutex_leave(p.pDestDb.mutex);
            }
            sqlite3BtreeLeave(p.pSrc);
            sqlite3_mutex_leave(p.pSrcDb.mutex);
            return(rc);
        }
Esempio n. 9
0
 /*
 ** Return the number of pages still to be backed up as of the most recent
 ** call to sqlite3_backup_step().
 */
 static int sqlite3_backup_remaining(sqlite3_backup p)
 {
     return((int)p.nRemaining);
 }
Esempio n. 10
0
 public static int pagecount(this sqlite3_backup backup)
 {
     return(raw.sqlite3_backup_pagecount(backup));
 }
Esempio n. 11
0
        /*
        ** Parameter zSrcData points to a buffer containing the data for
        ** page iSrcPg from the source database. Copy this data into the
        ** destination database.
        */
        private static int backupOnePage(sqlite3_backup p, uint iSrcPg, byte[] zSrcData)
        {
            var pDestPager = sqlite3BtreePager(p.pDest);
            var nSrcPgsz   = sqlite3BtreeGetPageSize(p.pSrc);
            var nDestPgsz  = sqlite3BtreeGetPageSize(p.pDest);
            var nCopy      = MIN(nSrcPgsz, nDestPgsz);
            var iEnd       = iSrcPg * nSrcPgsz;

            var  rc = SQLITE_OK;
            long iOff;

            Debug.Assert(p.bDestLocked != 0);
            Debug.Assert(!isFatalError(p.rc));
            Debug.Assert(iSrcPg != PENDING_BYTE_PAGE(p.pSrc.pBt));
            Debug.Assert(zSrcData != null);

            /* 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)))
            {
                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
            ** of the destination page.
            */
            for (iOff = iEnd - (long)nSrcPgsz; rc == SQLITE_OK && iOff < iEnd; iOff += nDestPgsz)
            {
                DbPage pDestPg = null;
                var    iDest   = (uint)(iOff / nDestPgsz) + 1;
                if (iDest == PENDING_BYTE_PAGE(p.pDest.pBt))
                {
                    continue;
                }
                if (SQLITE_OK == (rc = sqlite3PagerGet(pDestPager, iDest, ref pDestPg)) &&
                    SQLITE_OK == (rc = sqlite3PagerWrite(pDestPg))
                    )
                {
                    //string zIn = &zSrcData[iOff%nSrcPgsz];
                    var zDestData = sqlite3PagerGetData(pDestPg);
                    //string zOut = &zDestData[iOff % nDestPgsz];

                    /* Copy the data from the source page into the destination page.
                    ** Then clear the Btree layer MemPage.isInit flag. Both this module
                    ** and the pager code use this trick (clearing the first byte
                    ** of the page 'extra' space to invalidate the Btree layers
                    ** cached parse of the page). MemPage.isInit is marked
                    ** "MUST BE FIRST" for this purpose.
                    */
                    Buffer.BlockCopy(zSrcData, (int)(iOff % nSrcPgsz), zDestData, (int)(iOff % nDestPgsz),
                                     nCopy);                  // memcpy( zOut, zIn, nCopy );
                    sqlite3PagerGetExtra(pDestPg).isInit = 0; // ( sqlite3PagerGetExtra( pDestPg ) )[0] = 0;
                }

                sqlite3PagerUnref(pDestPg);
            }

            return(rc);
        }
Esempio n. 12
0
 public static int remaining(this sqlite3_backup backup)
 {
     return(raw.sqlite3_backup_remaining(backup));
 }
Esempio n. 13
0
 public static int finish(this sqlite3_backup backup)
 {
     return(raw.sqlite3_backup_finish(backup));
 }
Esempio n. 14
0
 public static int step(this sqlite3_backup backup, int nPage)
 {
     return(raw.sqlite3_backup_step(backup, nPage));
 }
Esempio n. 15
0
 /*
 ** Attempt to set the page size of the destination to match the page size
 ** of the source.
 */
 static int setDestPgsz( sqlite3_backup p )
 {
   int rc;
   rc = sqlite3BtreeSetPageSize( p.pDest, sqlite3BtreeGetPageSize( p.pSrc ), -1, 0 );
   return rc;
 }
Esempio n. 16
0
 /*
 ** Return the total number of pages in the source database as of the most
 ** recent call to sqlite3_backup_step().
 */
 static int sqlite3_backup_pagecount(sqlite3_backup p)
 {
     return((int)p.nPagecount);
 }
Esempio n. 17
0
    /*
    ** Create an sqlite3_backup process to copy the contents of zSrcDb from
    ** connection handle pSrcDb to zDestDb in pDestDb. If successful, return
    ** a pointer to the new sqlite3_backup object.
    **
    ** If an error occurs, NULL is returned and an error code and error message
    ** stored in database handle pDestDb.
    */
    static public sqlite3_backup sqlite3_backup_init(
    sqlite3 pDestDb,                 /* Database to write to */
    string zDestDb,                  /* Name of database within pDestDb */
    sqlite3 pSrcDb,                  /* Database connection to read from */
    string zSrcDb                    /* Name of database within pSrcDb */
    )
    {
      sqlite3_backup p;                    /* Value to return */

      /* Lock the source database handle. The destination database
      ** handle is not locked in this routine, but it is locked in
      ** sqlite3_backup_step(). The user is required to ensure that no
      ** other thread accesses the destination handle for the duration
      ** of the backup operation.  Any attempt to use the destination
      ** database connection while a backup is in progress may cause
      ** a malfunction or a deadlock.
      */
      sqlite3_mutex_enter( pSrcDb.mutex );
      sqlite3_mutex_enter( pDestDb.mutex );

      if ( pSrcDb == pDestDb )
      {
        sqlite3Error(
        pDestDb, SQLITE_ERROR, "source and destination must be distinct"
        );
        p = null;
      }
      else
      {
        /* 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 = new sqlite3_backup();// (sqlite3_backup)sqlite3_malloc( sizeof( sqlite3_backup ) );
        //if ( null == p )
        //{
        //  sqlite3Error( pDestDb, SQLITE_NOMEM, 0 );
        //}
      }

      /* If the allocation succeeded, populate the new object. */
      if ( p != null )
      {
        // memset( p, 0, sizeof( sqlite3_backup ) );
        p.pSrc = findBtree( pDestDb, pSrcDb, zSrcDb );
        p.pDest = findBtree( pDestDb, pDestDb, zDestDb );
        p.pDestDb = pDestDb;
        p.pSrcDb = pSrcDb;
        p.iNext = 1;
        p.isAttached = 0;

        if ( null == p.pSrc || null == p.pDest || setDestPgsz( p ) == SQLITE_NOMEM )
        {
          /* One (or both) of the named databases did not exist or an OOM
          ** error was hit.  The error has already been written into the
          ** pDestDb handle.  All that is left to do here is free the
          ** sqlite3_backup structure.
          */
          //sqlite3_free( ref p );
          p = null;
        }
      }

      if ( p != null )
      {
        p.pSrc.nBackup++;
      }

      sqlite3_mutex_leave( pDestDb.mutex );
      sqlite3_mutex_leave( pSrcDb.mutex );
      return p;
    }
Esempio n. 18
0
 public static Result BackupStep(sqlite3_backup backup, int numPages)
 {
     return((Result)raw.sqlite3_backup_step(backup, numPages));
 }
Esempio n. 19
0
 /*
 ** Register this backup object with the associated source pager for
 ** callbacks when pages are changed or the cache invalidated.
 */
 static void attachBackupObject( sqlite3_backup p )
 {
   sqlite3_backup pp;
   Debug.Assert( sqlite3BtreeHoldsMutex( p.pSrc ) );
   pp = sqlite3PagerBackupPtr( sqlite3BtreePager( p.pSrc ) );
   p.pNext = pp;
   sqlite3BtreePager( p.pSrc ).pBackup = p; //*pp = p;
   p.isAttached = 1;
 }
Esempio n. 20
0
 public static Result BackupFinish(sqlite3_backup backup)
 {
     return((Result)raw.sqlite3_backup_finish(backup));
 }
Esempio n. 21
0
 /*
 ** Return the number of pages still to be backed up as of the most recent
 ** call to sqlite3_backup_step().
 */
 static int sqlite3_backup_remaining( sqlite3_backup p )
 {
   return (int)p.nRemaining;
 }
Esempio n. 22
0
/*
** Create an sqlite3_backup process to copy the contents of zSrcDb from
** connection handle pSrcDb to zDestDb in pDestDb. If successful, return
** a pointer to the new sqlite3_backup object.
**
** If an error occurs, NULL is returned and an error code and error message
** stored in database handle pDestDb.
*/
        static public sqlite3_backup sqlite3_backup_init(
            sqlite3 pDestDb,     /* Database to write to */
            string zDestDb,      /* Name of database within pDestDb */
            sqlite3 pSrcDb,      /* Database connection to read from */
            string zSrcDb        /* Name of database within pSrcDb */
            )
        {
            sqlite3_backup p;          /* Value to return */

            /* Lock the source database handle. The destination database
            ** handle is not locked in this routine, but it is locked in
            ** sqlite3_backup_step(). The user is required to ensure that no
            ** other thread accesses the destination handle for the duration
            ** of the backup operation.  Any attempt to use the destination
            ** database connection while a backup is in progress may cause
            ** a malfunction or a deadlock.
            */
            sqlite3_mutex_enter(pSrcDb.mutex);
            sqlite3_mutex_enter(pDestDb.mutex);

            if (pSrcDb == pDestDb)
            {
                sqlite3Error(
                    pDestDb, SQLITE_ERROR, "source and destination must be distinct"
                    );
                p = null;
            }
            else
            {
                /* 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 = new sqlite3_backup();// (sqlite3_backup)sqlite3_malloc( sizeof( sqlite3_backup ) );
                //if ( null == p )
                //{
                //  sqlite3Error( pDestDb, SQLITE_NOMEM, 0 );
                //}
            }

            /* If the allocation succeeded, populate the new object. */
            if (p != null)
            {
                // memset( p, 0, sizeof( sqlite3_backup ) );
                p.pSrc       = findBtree(pDestDb, pSrcDb, zSrcDb);
                p.pDest      = findBtree(pDestDb, pDestDb, zDestDb);
                p.pDestDb    = pDestDb;
                p.pSrcDb     = pSrcDb;
                p.iNext      = 1;
                p.isAttached = 0;

                if (null == p.pSrc || null == p.pDest || setDestPgsz(p) == SQLITE_NOMEM)
                {
                    /* One (or both) of the named databases did not exist or an OOM
                    ** error was hit.  The error has already been written into the
                    ** pDestDb handle.  All that is left to do here is free the
                    ** sqlite3_backup structure.
                    */
                    //sqlite3_free( ref p );
                    p = null;
                }
            }

            if (p != null)
            {
                p.pSrc.nBackup++;
            }

            sqlite3_mutex_leave(pDestDb.mutex);
            sqlite3_mutex_leave(pSrcDb.mutex);
            return(p);
        }
Esempio n. 23
0
 /*
 ** This function is called after the contents of page iPage of the
 ** source database have been modified. If page iPage has already been
 ** copied into the destination database, then the data written to the
 ** destination is now invalidated. The destination copy of iPage needs
 ** to be updated with the new data before the backup operation is
 ** complete.
 **
 ** It is assumed that the mutex associated with the BtShared object
 ** corresponding to the source database is held when this function is
 ** called.
 */
 static void sqlite3BackupUpdate( sqlite3_backup pBackup, Pgno iPage, byte[] aData )
 {
   sqlite3_backup p;                   /* Iterator variable */
   for ( p = pBackup; p != null; p = p.pNext )
   {
     Debug.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
       ** the new data into the backup.
       */
       int rc = backupOnePage( p, iPage, aData );
       Debug.Assert( rc != SQLITE_BUSY && rc != SQLITE_LOCKED );
       if ( rc != SQLITE_OK )
       {
         p.rc = rc;
       }
     }
   }
 }
Esempio n. 24
0
/*
** Parameter zSrcData points to a buffer containing the data for
** page iSrcPg from the source database. Copy this data into the
** destination database.
*/
        static int backupOnePage(sqlite3_backup p, Pgno iSrcPg, byte[] zSrcData)
        {
            Pager pDestPager = sqlite3BtreePager(p.pDest);
            int   nSrcPgsz   = sqlite3BtreeGetPageSize(p.pSrc);
            int   nDestPgsz  = sqlite3BtreeGetPageSize(p.pDest);
            int   nCopy      = MIN(nSrcPgsz, nDestPgsz);
            i64   iEnd       = (i64)iSrcPg * (i64)nSrcPgsz;

#if SQLITE_HAS_CODEC
            int nSrcReserve  = sqlite3BtreeGetReserve(p.pSrc);
            int nDestReserve = sqlite3BtreeGetReserve(p.pDest);
#endif

            int rc = SQLITE_OK;
            i64 iOff;

            Debug.Assert(p.bDestLocked != 0);
            Debug.Assert(!isFatalError(p.rc));
            Debug.Assert(iSrcPg != PENDING_BYTE_PAGE(p.pSrc.pBt));
            Debug.Assert(zSrcData != null);

            /* 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(pDestPager))
            {
                rc = SQLITE_READONLY;
            }

#if SQLITE_HAS_CODEC
            /* Backup is not possible if the page size of the destination is changing
            ** and a codec is in use.
            */
            if (nSrcPgsz != nDestPgsz && sqlite3PagerGetCodec(pDestPager) != null)
            {
                rc = SQLITE_READONLY;
            }

            /* Backup is not possible if the number of bytes of reserve space differ
            ** between source and destination.  If there is a difference, try to
            ** fix the destination to agree with the source.  If that is not possible,
            ** then the backup cannot proceed.
            */
            if (nSrcReserve != nDestReserve)
            {
                u32 newPgsz = (u32)nSrcPgsz;
                rc = sqlite3PagerSetPagesize(pDestPager, ref newPgsz, nSrcReserve);
                if (rc == SQLITE_OK && newPgsz != nSrcPgsz)
                {
                    rc = SQLITE_READONLY;
                }
            }
#endif

            /* This loop runs once for each destination page spanned by the source
            ** page. For each iteration, variable iOff is set to the byte offset
            ** of the destination page.
            */
            for (iOff = iEnd - (i64)nSrcPgsz; rc == SQLITE_OK && iOff < iEnd; iOff += nDestPgsz)
            {
                DbPage pDestPg = null;
                u32    iDest   = (u32)(iOff / nDestPgsz) + 1;
                if (iDest == PENDING_BYTE_PAGE(p.pDest.pBt))
                {
                    continue;
                }
                if (SQLITE_OK == (rc = sqlite3PagerGet(pDestPager, iDest, ref pDestPg)) &&
                    SQLITE_OK == (rc = sqlite3PagerWrite(pDestPg))
                    )
                {
                    //string zIn = &zSrcData[iOff%nSrcPgsz];
                    byte[] zDestData = sqlite3PagerGetData(pDestPg);
                    //string zOut = &zDestData[iOff % nDestPgsz];

                    /* Copy the data from the source page into the destination page.
                    ** Then clear the Btree layer MemPage.isInit flag. Both this module
                    ** and the pager code use this trick (clearing the first byte
                    ** of the page 'extra' space to invalidate the Btree layers
                    ** cached parse of the page). MemPage.isInit is marked
                    ** "MUST BE FIRST" for this purpose.
                    */
                    Buffer.BlockCopy(zSrcData, (int)(iOff % nSrcPgsz), zDestData, (int)(iOff % nDestPgsz), nCopy); // memcpy( zOut, zIn, nCopy );
                    sqlite3PagerGetExtra(pDestPg).isInit = 0;                                                      // ( sqlite3PagerGetExtra( pDestPg ) )[0] = 0;
                }
                sqlite3PagerUnref(pDestPg);
            }

            return(rc);
        }
Esempio n. 25
0
    /*
** Copy the complete content of pBtFrom into pBtTo.  A transaction
** must be active for both files.
**
** The size of file pTo may be reduced by this operation. If anything
** goes wrong, the transaction on pTo is rolled back. If successful, the
** transaction is committed before returning.
*/
    static int sqlite3BtreeCopyFile( Btree pTo, Btree pFrom )
    {
      int rc;
      sqlite3_backup b;
      sqlite3BtreeEnter( pTo );
      sqlite3BtreeEnter( pFrom );

      /* Set up an sqlite3_backup object. sqlite3_backup.pDestDb must be set
      ** to 0. This is used by the implementations of sqlite3_backup_step()
      ** and sqlite3_backup_finish() to detect that they are being called
      ** from this function, not directly by the user.
      */
      b = new sqlite3_backup();// memset( &b, 0, sizeof( b ) );
      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
      ** file. By passing this as the number of pages to copy to
      ** sqlite3_backup_step(), we can guarantee that the copy finishes
      ** within a single call (unless an error occurs). The Debug.Assert() statement
      ** checks this assumption - (p.rc) should be set to either SQLITE_DONE
      ** or an error code.
      */
      sqlite3_backup_step( b, 0x7FFFFFFF );
      Debug.Assert( b.rc != SQLITE_OK );
      rc = sqlite3_backup_finish( b );
      if ( rc == SQLITE_OK )
      {
        pTo.pBt.pageSizeFixed = false;
      }

      sqlite3BtreeLeave( pFrom );
      sqlite3BtreeLeave( pTo );
      return rc;
    }
Esempio n. 26
0
        static void backupTestFinish(ref ClientData clientData)
        {
            sqlite3_backup pBackup = (sqlite3_backup)clientData;

            sqlite3_backup_finish(pBackup);
        }