Browse Source

* Sqlite3backup, implements backups between 2 TSQLite3Connections, TSQLite3Connection backup to file and TSQLite3Connection restore from file.
by Ludo Brands, mantis #22394

git-svn-id: trunk@22559 -

marco 13 years ago
parent
commit
7ec9f59e45
3 changed files with 168 additions and 1 deletions
  1. 1 0
      .gitattributes
  2. 6 1
      packages/fcl-db/fpmake.pp
  3. 161 0
      packages/fcl-db/src/sqlite/sqlite3backup.pas

+ 1 - 0
.gitattributes

@@ -2086,6 +2086,7 @@ packages/fcl-db/src/sqlite/customsqliteds.pas svneol=native#text/plain
 packages/fcl-db/src/sqlite/fillds.pas svneol=native#text/plain
 packages/fcl-db/src/sqlite/fillds.pas svneol=native#text/plain
 packages/fcl-db/src/sqlite/fpmake.inc svneol=native#text/plain
 packages/fcl-db/src/sqlite/fpmake.inc svneol=native#text/plain
 packages/fcl-db/src/sqlite/fpmake.pp svneol=native#text/plain
 packages/fcl-db/src/sqlite/fpmake.pp svneol=native#text/plain
+packages/fcl-db/src/sqlite/sqlite3backup.pas svneol=native#text/plain
 packages/fcl-db/src/sqlite/sqlite3ds.pas svneol=native#text/plain
 packages/fcl-db/src/sqlite/sqlite3ds.pas svneol=native#text/plain
 packages/fcl-db/src/sqlite/sqliteds.pas svneol=native#text/plain
 packages/fcl-db/src/sqlite/sqliteds.pas svneol=native#text/plain
 packages/fcl-db/src/sqlite/testds.pas svneol=native#text/plain
 packages/fcl-db/src/sqlite/testds.pas svneol=native#text/plain

+ 6 - 1
packages/fcl-db/fpmake.pp

@@ -456,6 +456,7 @@ begin
           AddUnit('db');
           AddUnit('db');
           AddUnit('dbconst');
           AddUnit('dbconst');
         end;
         end;
+
     T:=P.Targets.AddUnit('fpddsqldb.pp', DatadictOSes);
     T:=P.Targets.AddUnit('fpddsqldb.pp', DatadictOSes);
     T.ResourceStrings:=true;
     T.ResourceStrings:=true;
       with T.Dependencies do
       with T.Dependencies do
@@ -716,7 +717,11 @@ begin
           AddUnit('customsqliteds');
           AddUnit('customsqliteds');
           AddUnit('db');
           AddUnit('db');
         end;
         end;
-
+    T:=P.Targets.AddUnit('sqlite3backup.pas', SqliteOSes);
+      with T.Dependencies do
+        begin
+          AddUnit('sqlite3conn');
+        end;
     // SQL
     // SQL
     T:=P.Targets.AddUnit('fpsqltree.pp');
     T:=P.Targets.AddUnit('fpsqltree.pp');
     T:=P.Targets.AddUnit('fpsqlscanner.pp');
     T:=P.Targets.AddUnit('fpsqlscanner.pp');

+ 161 - 0
packages/fcl-db/src/sqlite/sqlite3backup.pas

@@ -0,0 +1,161 @@
+unit sqlite3backup;
+
+{ SQLite3 backup class.
+
+  Copyright (C) 2012 Ludo Brands
+
+  This library is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Library General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or (at your
+  option) any later version with the following modification:
+
+  As a special exception, the copyright holders of this library give you
+  permission to link this library with independent modules to produce an
+  executable, regardless of the license terms of these independent modules,and
+  to copy and distribute the resulting executable under terms of your choice,
+  provided that you also meet, for each linked independent module, the terms
+  and conditions of the license of that module. An independent module is a
+  module which is not derived from or based on this library. If you modify
+  this library, you may extend this exception to your version of the library,
+  but you are not obligated to do so. If you do not wish to do so, delete this
+  exception statement from your version.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
+  for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; if not, write to the Free Software Foundation,
+  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+}
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils,sqlite3conn,sqlite3dyn;
+
+type
+
+  TOnBackupProgress = procedure (Sender: TObject; Remaining, PageCount: integer) of object;
+
+  { TSQLite3Backup }
+
+  TSQLite3Backup=class
+  private
+    FErrorMessage: string;
+    FLockReleaseTime: integer;
+    FOnBackupProgress: TOnBackupProgress;
+    FPageStep: integer;
+  public
+    constructor Create;
+    //Backup one TSQLite3Connection to another TSQLite3Connection
+    //SourceDBName and DestinationDBName is "main" for the main database, "temp" for the temporary
+    //database, or the name specified after the AS keyword in an ATTACH statement for an
+    //attached database
+    //LockUntilFinished: Set to false when simultanuous access from other processes is required.
+    //The backup process will restart when another process writes to the database.
+    //Pro: the backup is a correct snapshot
+    //Contra: the backup can take a very long time when a lot of writes to the database are made during backup
+    //Warning: don't use the destination TSQLite3Connection (the handle) for anything else while doing a backup.
+    //It can corrupt the database and even cause a mutex deadlock.
+    function Backup(Source,Destination:TSQLite3Connection;LockUntilFinished:boolean=true;
+         SourceDBName:string='main';DestinationDBName:string='main'):boolean;
+    //Backup a database to file
+    function Backup(Source:TSQLite3Connection;FileName:string;LockUntilFinished:boolean=true;
+         SourceDBName:string='main'):boolean;
+    //Restore a database from file
+    function Restore(FileName:string;Destination:TSQLite3Connection;LockUntilFinished:boolean=true;
+         DestinationDBName:string='main'):boolean;
+  published
+    //Delay between backup steps in ms. Default:100ms. Only used when LockUntilFinished=false
+    property LockReleaseTime:integer read FLockReleaseTime write FLockReleaseTime;
+    //Page size between backup steps. Default:10 Only used when LockUntilFinished=false
+    property PageStep:integer read FPageStep write FPageStep;
+    property ErrorMessage:string read FErrorMessage;
+    property OnBackupProgress:TOnBackupProgress read FOnBackupProgress write FOnBackupProgress;
+  end;
+
+implementation
+
+
+
+
+{ TSQLite3Backup }
+
+constructor TSQLite3Backup.Create;
+begin
+  FLockReleaseTime:=100;
+  FPageStep:=10;
+end;
+
+function TSQLite3Backup.Backup(Source, Destination: TSQLite3Connection;
+  LockUntilFinished: boolean; SourceDBName: string; DestinationDBName: string
+  ): boolean;
+var
+  pBackup:psqlite3backup;
+  nPage:integer;
+  res: integer;
+begin
+   FErrorMessage:='';
+   Source.Connected:=true;
+   Destination.Connected:=true;
+   pBackup := sqlite3_backup_init(Destination.Handle, pchar(DestinationDBName),
+      Source.Handle, pchar(SourceDBName));
+   if LockUntilFinished then
+     nPage:=-1
+   else
+     nPage:=FPageStep;
+   result:=false;
+   if assigned(pBackup) then
+     begin
+{  Each iteration of this loop copies PageStep database pages from database
+   pDb to the backup database. If the return value of backup_step()
+   indicates that there are still further pages to copy, sleep for
+   LockReleaseTime ms before repeating. }
+     repeat
+       res := sqlite3_backup_step(pBackup, nPage);
+       if assigned(FOnBackupProgress) then
+         FOnBackupProgress(self,sqlite3_backup_remaining(pBackup),
+           sqlite3_backup_pagecount(pBackup));
+       if not LockUntilFinished and (res in [SQLITE_OK,SQLITE_BUSY,SQLITE_LOCKED]) then
+         sqlite3_sleep(LockReleaseTime);
+     until LockUntilFinished or not (res in [SQLITE_OK,SQLITE_BUSY,SQLITE_LOCKED]);
+     result:=sqlite3_backup_finish(pBackup)=SQLITE_OK;
+     end;
+   if not result then
+     FErrorMessage:=strpas(sqlite3_errmsg(Destination.Handle));
+end;
+
+function TSQLite3Backup.Backup(Source: TSQLite3Connection; FileName: string;
+  LockUntilFinished: boolean; SourceDBName: string): boolean;
+var conn:TSQLite3Connection;
+begin
+  conn:=TSQLite3Connection.Create(nil);
+  try
+    conn.DatabaseName:=FileName;
+    conn.Connected:=true;
+    result:=Backup(Source,conn,LockUntilFinished,SourceDBName);
+  finally
+    conn.Destroy;
+  end;
+end;
+
+function TSQLite3Backup.Restore(FileName: string;
+  Destination: TSQLite3Connection; LockUntilFinished: boolean;
+  DestinationDBName: string): boolean;
+var conn:TSQLite3Connection;
+begin
+  conn:=TSQLite3Connection.Create(nil);
+  try
+    conn.DatabaseName:=FileName;
+    conn.Connected:=true;
+    result:=Backup(conn,Destination,LockUntilFinished,'main',DestinationDBName);
+  finally
+    conn.Destroy;
+  end;
+end;
+
+end.
+