System.Data.SQLite
Check-in [5f8913872b]
Not logged in

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

Overview
Comment:Add more backup API test cases. Modify BackupDatabase method to prevent looping when the number of pages is zero. Modify SQLiteBackupCallback delegate to accept additional context information and move it outside the scope of the SQLiteConnection class.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 5f8913872b9b87ea5032cd5de22fc904b79cbe82
User & Date: mistachkin 2012-03-26 09:14:57
Context
2012-03-26
09:18
Make all the dynamic test classes static, when possible. check-in: 3f6ed3b646 user: mistachkin tags: trunk
09:14
Add more backup API test cases. Modify BackupDatabase method to prevent looping when the number of pages is zero. Modify SQLiteBackupCallback delegate to accept additional context information and move it outside the scope of the SQLiteConnection class. check-in: 5f8913872b user: mistachkin tags: trunk
2012-03-24
16:48
Add support for the native SQLite Online Backup API. check-in: 4926b5d713 user: mistachkin tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to System.Data.SQLite/SQLiteConnection.cs.

   329    329           }
   330    330         }
   331    331       }
   332    332   
   333    333       ///////////////////////////////////////////////////////////////////////////////////////////////
   334    334   
   335    335       #region Backup API Members
   336         -    /// <summary>
   337         -    /// Raised between each backup step.
   338         -    /// </summary>
   339         -    /// <param name="source">
   340         -    /// The source database connection.
   341         -    /// </param>
   342         -    /// <param name="destination">
   343         -    /// The destination database connection.
   344         -    /// </param>
   345         -    /// <param name="remainingPages">
   346         -    /// The number of pages remaining to be copied.
   347         -    /// </param>
   348         -    /// <param name="totalPages">
   349         -    /// The total number of pages in the source database.
   350         -    /// </param>
   351         -    /// <param name="retry">
   352         -    /// Set to true if the operation needs to be retried due to database
   353         -    /// locking issues; otherwise, set to false.
   354         -    /// </param>
   355         -    /// <returns>
   356         -    /// True to continue with the backup process or false to halt the backup
   357         -    /// process, rolling back any changes that have been made so far.
   358         -    /// </returns>
   359         -    public delegate bool SQLiteBackupCallback(
   360         -        SQLiteConnection source, SQLiteConnection destination,
   361         -        int remainingPages, int totalPages, bool retry);
   362         -
   363         -    ///////////////////////////////////////////////////////////////////////////////////////////////
   364         -
   365    336       /// <summary>
   366    337       /// Backs up the database, using the specified database connection as the
   367    338       /// destination.
   368    339       /// </summary>
   369    340       /// <param name="destination">The destination database connection.</param>
   370    341       /// <param name="destinationName">The destination database name.</param>
   371    342       /// <param name="sourceName">The source database name.</param>
   372         -    /// <param name="nPage">
          343  +    /// <param name="pages">
   373    344       /// The number of pages to copy or negative to copy all remaining pages.
   374    345       /// </param>
   375    346       /// <param name="callback">
   376    347       /// The method to invoke between each step of the backup process.  This
   377    348       /// parameter may be null (i.e. no callbacks will be performed).
   378    349       /// </param>
   379    350       /// <param name="retryMilliseconds">
................................................................................
   381    352       /// during the backup process.  A value less than zero means that no sleep
   382    353       /// should be performed.
   383    354       /// </param>
   384    355       public void BackupDatabase(
   385    356           SQLiteConnection destination,
   386    357           string destinationName,
   387    358           string sourceName,
   388         -        int nPage,
          359  +        int pages,
   389    360           SQLiteBackupCallback callback,
   390    361           int retryMilliseconds
   391    362           )
   392    363       {
   393    364           CheckDisposed();
   394    365   
   395    366           if (_connectionState != ConnectionState.Open)
................................................................................
   420    391           try
   421    392           {
   422    393               backup = sqliteBase.InitializeBackup(
   423    394                   destination, destinationName, sourceName); /* throw */
   424    395   
   425    396               bool retry;
   426    397   
   427         -            while (sqliteBase.StepBackup(backup, nPage, out retry)) /* throw */
          398  +            while (sqliteBase.StepBackup(backup, pages, out retry)) /* throw */
   428    399               {
   429    400                   //
   430    401                   // NOTE: If a callback was supplied by our caller, call it.
   431    402                   //       If it returns false, halt the backup process.
   432    403                   //
   433         -                if ((callback != null) && !callback(this,
   434         -                        destination, sqliteBase.RemainingBackup(backup),
          404  +                if ((callback != null) && !callback(this, sourceName,
          405  +                        destination, destinationName, pages,
          406  +                        sqliteBase.RemainingBackup(backup),
   435    407                           sqliteBase.PageCountBackup(backup), retry))
   436    408                   {
   437    409                       break;
   438    410                   }
   439    411   
   440    412                   //
   441    413                   // NOTE: If we need to retry the previous operation, wait for
................................................................................
   442    414                   //       the number of milliseconds specified by our caller
   443    415                   //       unless the caller used a negative number, in that case
   444    416                   //       skip sleeping at all because we do not want to block
   445    417                   //       this thread forever.
   446    418                   //
   447    419                   if (retry && (retryMilliseconds >= 0))
   448    420                       System.Threading.Thread.Sleep(retryMilliseconds);
          421  +
          422  +                //
          423  +                // NOTE: There is no point in calling the native API to copy
          424  +                //       zero pages as it does nothing; therefore, stop now.
          425  +                //
          426  +                if (pages == 0)
          427  +                    break;
   449    428               }
   450    429           }
   451    430           catch (Exception e)
   452    431           {
   453    432   #if !PLATFORM_COMPACTFRAMEWORK
   454    433               if ((_flags & SQLiteConnectionFlags.LogBackup) == SQLiteConnectionFlags.LogBackup)
   455    434               {
................................................................................
  2859   2838   
  2860   2839     /// <summary>
  2861   2840     /// Raised when a statement first begins executing on a given connection
  2862   2841     /// </summary>
  2863   2842     /// <param name="sender">The connection executing the statement</param>
  2864   2843     /// <param name="e">Event arguments of the trace</param>
  2865   2844     public delegate void SQLiteTraceEventHandler(object sender, TraceEventArgs e);
         2845  +
         2846  +  ///////////////////////////////////////////////////////////////////////////////////////////////
         2847  +
         2848  +  #region Backup API Members
         2849  +  /// <summary>
         2850  +  /// Raised between each backup step.
         2851  +  /// </summary>
         2852  +  /// <param name="source">
         2853  +  /// The source database connection.
         2854  +  /// </param>
         2855  +  /// <param name="sourceName">
         2856  +  /// The source database name.
         2857  +  /// </param>
         2858  +  /// <param name="destination">
         2859  +  /// The destination database connection.
         2860  +  /// </param>
         2861  +  /// <param name="destinationName">
         2862  +  /// The destination database name.
         2863  +  /// </param>
         2864  +  /// <param name="pages">
         2865  +  /// The number of pages copied with each step.
         2866  +  /// </param>
         2867  +  /// <param name="remainingPages">
         2868  +  /// The number of pages remaining to be copied.
         2869  +  /// </param>
         2870  +  /// <param name="totalPages">
         2871  +  /// The total number of pages in the source database.
         2872  +  /// </param>
         2873  +  /// <param name="retry">
         2874  +  /// Set to true if the operation needs to be retried due to database
         2875  +  /// locking issues; otherwise, set to false.
         2876  +  /// </param>
         2877  +  /// <returns>
         2878  +  /// True to continue with the backup process or false to halt the backup
         2879  +  /// process, rolling back any changes that have been made so far.
         2880  +  /// </returns>
         2881  +  public delegate bool SQLiteBackupCallback(
         2882  +    SQLiteConnection source,
         2883  +    string sourceName,
         2884  +    SQLiteConnection destination,
         2885  +    string destinationName,
         2886  +    int pages,
         2887  +    int remainingPages,
         2888  +    int totalPages,
         2889  +    bool retry
         2890  +  );
         2891  +  #endregion
         2892  +
         2893  +  ///////////////////////////////////////////////////////////////////////////////////////////////
  2866   2894   
  2867   2895     /// <summary>
  2868   2896     /// Whenever an update event is triggered on a connection, this enum will indicate
  2869   2897     /// exactly what type of operation is being performed.
  2870   2898     /// </summary>
  2871   2899     public enum UpdateEventType
  2872   2900     {

Changes to Tests/backup.eagle.

    16     16   ###############################################################################
    17     17   
    18     18   package require System.Data.SQLite.Test
    19     19   runSQLiteTestPrologue
    20     20   
    21     21   ###############################################################################
    22     22   
    23         -runTest {test backup-1.1 {BackupDatabase method, memory to disk} -setup {
    24         -  setupDb [set fileName(1) :memory:] "" "" "" "" "" false memDb
    25         -  setupDb [set fileName(2) backup-1.1.db]
    26         -} -body {
    27         -  set id [object invoke Interpreter.GetActive NextId]
    28         -  set dataSource [file join [getDatabaseDirectory] $fileName(2)]
    29         -
    30         -  sql execute $memDb {
    31         -    CREATE TABLE t1(x TEXT);
    32         -  }
    33         -
    34         -  for {set index 0} {$index < 10} {incr index} {
    35         -    sql execute $memDb [subst {
    36         -      INSERT INTO t1 (x) VALUES('[string repeat ! 1048576]');
    37         -    }]
    38         -  }
    39         -
    40         -  set memSource [object invoke -flags +NonPublic -objectflags +NoDispose \
    41         -      Interpreter.GetActive.connections get_Item $memDb]
    42         -
    43         -  unset -nocomplain results errors
    44         -
    45         -  set code [compileCSharpWith [subst {
    46         -    using System.Data.SQLite;
    47         -    using System.Text;
    48         -
    49         -    namespace _Dynamic${id}
    50         -    {
    51         -      public class Test${id}
           23  +set params(pages) [list -1 -1 0 0 1 1 1000 1000]
           24  +
           25  +set params(callbacks) [list null "new SQLiteBackupCallback(BackupCallback)" \
           26  +                            null "new SQLiteBackupCallback(BackupCallback)" \
           27  +                            null "new SQLiteBackupCallback(BackupCallback)" \
           28  +                            null "new SQLiteBackupCallback(BackupCallback)"]
           29  +
           30  +set params(results) [list \
           31  +    "0 \\{1 1048576 1048576 1048576 1048576 1048576 1048576 1048576 1048576\
           32  +    1048576 1048576 10\\} 0\$" \
           33  +    "0 \\{1 1048576 1048576 1048576 1048576 1048576 1048576 1048576 1048576\
           34  +    1048576 1048576 10\\} 0\$" \
           35  +    "1 \\{System\\.Reflection\\.TargetInvocationException: Exception has been\
           36  +    thrown by the target of an invocation\\. --->\
           37  +    System\\.Data\\.SQLite\\.SQLiteException: SQLite error\\r\\nno such table:\
           38  +    t1\\r\\n.*?" \
           39  +    "1 \\{System\\.Reflection\\.TargetInvocationException: Exception has been\
           40  +    thrown by the target of an invocation\\. --->\
           41  +    System\\.Data\\.SQLite\\.SQLiteException: SQLite error\\r\\nno such table:\
           42  +    t1\\r\\n.*?" \
           43  +    "0 \\{1 1048576 1048576 1048576 1048576 1048576 1048576 1048576 1048576\
           44  +    1048576 1048576 10\\} 0\$" \
           45  +    "0 \\{1 1048576 1048576 1048576 1048576 1048576 1048576 1048576 1048576\
           46  +    1048576 1048576 10\\} 10283\$" \
           47  +    "0 \\{1 1048576 1048576 1048576 1048576 1048576 1048576 1048576 1048576\
           48  +    1048576 1048576 10\\} \\{\\}\$" \
           49  +    "0 \\{1 1048576 1048576 1048576 1048576 1048576 1048576 1048576 1048576\
           50  +    1048576 1048576 10\\} \\{System\\.Data\\.SQLite\\.SQLiteConnection main\
           51  +    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 9284 10284 False\
           52  +    System\\.Data\\.SQLite\\.SQLiteConnection main\
           53  +    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 8284 10284 False\
           54  +    System\\.Data\\.SQLite\\.SQLiteConnection main\
           55  +    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 7284 10284 False\
           56  +    System\\.Data\\.SQLite\\.SQLiteConnection main\
           57  +    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 6284 10284 False\
           58  +    System\\.Data\\.SQLite\\.SQLiteConnection main\
           59  +    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 5284 10284 False\
           60  +    System\\.Data\\.SQLite\\.SQLiteConnection main\
           61  +    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 4284 10284 False\
           62  +    System\\.Data\\.SQLite\\.SQLiteConnection main\
           63  +    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 3284 10284 False\
           64  +    System\\.Data\\.SQLite\\.SQLiteConnection main\
           65  +    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 2284 10284 False\
           66  +    System\\.Data\\.SQLite\\.SQLiteConnection main\
           67  +    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 1284 10284 False\
           68  +    System\\.Data\\.SQLite\\.SQLiteConnection main\
           69  +    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 284 10284 False\\}\$"]
           70  +
           71  +###############################################################################
           72  +
           73  +for {set i 0} {$i < [llength $params(pages)]} {incr i} {
           74  +  set pages [lindex $params(pages) $i]
           75  +  set callback [lindex $params(callbacks) $i]
           76  +
           77  +  runTest {test [appendArgs backup-1. $i] {BackupDatabase method} -setup {
           78  +    setupDb [set fileName(1) :memory:] "" "" "" "" "" false memDb
           79  +    setupDb [set fileName(2) [appendArgs backup-1. $i .db]]
           80  +  } -body {
           81  +    set id [object invoke Interpreter.GetActive NextId]
           82  +    set dataSource [file join [getDatabaseDirectory] $fileName(2)]
           83  +
           84  +    sql execute $memDb {
           85  +      CREATE TABLE t1(x TEXT);
           86  +    }
           87  +
           88  +    for {set index 0} {$index < 10} {incr index} {
           89  +      sql execute $memDb [subst {
           90  +        INSERT INTO t1 (x) VALUES('[string repeat ! 1048576]');
           91  +      }]
           92  +    }
           93  +
           94  +    set memSource [object invoke -flags +NonPublic -objectflags +NoDispose \
           95  +        Interpreter.GetActive.connections get_Item $memDb]
           96  +
           97  +    unset -nocomplain results errors
           98  +
           99  +    set code [compileCSharpWith [subst {
          100  +      using System;
          101  +      using System.Data.SQLite;
          102  +      using System.Text;
          103  +      using Eagle._Components.Public;
          104  +
          105  +      namespace _Dynamic${id}
    52    106         {
    53         -        public static string GetRows(
    54         -          SQLiteConnection source
    55         -          )
          107  +        public static class Test${id}
    56    108           {
    57         -          using (SQLiteConnection destination = new SQLiteConnection(
    58         -              "Data Source=${dataSource};"))
          109  +          public static int count = 0;
          110  +          public static readonly StringBuilder results = new StringBuilder();
          111  +
          112  +          /////////////////////////////////////////////////////////////////////
          113  +
          114  +          public static bool BackupCallback(
          115  +            SQLiteConnection source,
          116  +            string sourceName,
          117  +            SQLiteConnection destination,
          118  +            string destinationName,
          119  +            int pages,
          120  +            int remainingPages,
          121  +            int totalPages,
          122  +            bool retry
          123  +            )
          124  +          {
          125  +            results.AppendFormat("{0} {1} {2} {3} {4} {5} {6} {7} ", source,
          126  +              sourceName, destination, destinationName, pages, remainingPages,
          127  +              totalPages, retry);
          128  +
          129  +            count++;
          130  +
          131  +            return true;
          132  +          }
          133  +
          134  +          /////////////////////////////////////////////////////////////////////
          135  +
          136  +          public static string BackupAndGetData(
          137  +            Interpreter interpreter,
          138  +            SQLiteConnection source
          139  +            )
    59    140             {
    60         -            destination.Open();
    61         -            source.BackupDatabase(destination, "main", "main", -1, null, 0);
    62         -
    63         -            using (SQLiteCommand command = new SQLiteCommand(
    64         -                "SELECT length(x) FROM t1;", destination))
          141  +            using (SQLiteConnection destination = new SQLiteConnection(
          142  +                "Data Source=${dataSource};"))
    65    143               {
    66         -              using (SQLiteDataReader dataReader = command.ExecuteReader())
          144  +              destination.Open();
          145  +
          146  +              int pages = ${pages};
          147  +
          148  +              source.BackupDatabase(destination, "main", "main", pages,
          149  +                ${callback}, 0);
          150  +
          151  +              ReturnCode code;
          152  +              Result error = null;
          153  +
          154  +              code = interpreter.SetVariableValue(
          155  +                VariableFlags.GlobalOnly, "callbackResults", (pages > 1) ?
          156  +                    results.ToString().Trim() : count.ToString(), null,
          157  +                ref error);
          158  +
          159  +              if (code != ReturnCode.Ok)
          160  +                Utility.Complain(interpreter, code, error);
          161  +
          162  +              using (SQLiteCommand command = new SQLiteCommand(
          163  +                  "SELECT length(x) FROM t1;", destination))
    67    164                 {
    68         -                int rowCount = 0;
    69         -                StringBuilder builder = new StringBuilder();
    70         -
    71         -                builder.Append(dataReader.FieldCount);
    72         -                builder.Append(' ');
    73         -
    74         -                while (dataReader.Read())
          165  +                using (SQLiteDataReader dataReader = command.ExecuteReader())
    75    166                   {
    76         -                  builder.Append(dataReader.GetInt64(0));
          167  +                  StringBuilder builder = new StringBuilder();
          168  +                  int rowCount = 0;
          169  +
          170  +                  builder.Append(dataReader.FieldCount);
    77    171                     builder.Append(' ');
    78         -                  rowCount++;
    79         -                }
          172  +
          173  +                  while (dataReader.Read())
          174  +                  {
          175  +                    builder.Append(dataReader.GetInt64(0));
          176  +                    builder.Append(' ');
          177  +                    rowCount++;
          178  +                  }
    80    179   
    81         -                builder.Append(rowCount);
    82         -                return builder.ToString();
          180  +                  builder.Append(rowCount);
          181  +                  return builder.ToString();
          182  +                }
    83    183                 }
    84    184               }
    85    185             }
    86         -        }
    87    186   
    88         -        ///////////////////////////////////////////////////////////////////////
          187  +          /////////////////////////////////////////////////////////////////////
    89    188   
    90         -        public static void Main()
    91         -        {
    92         -          // do nothing.
          189  +          public static void Main()
          190  +          {
          191  +            // do nothing.
          192  +          }
    93    193           }
    94    194         }
    95         -    }
    96         -  }] true true true results errors System.Data.SQLite.dll]
          195  +    }] true true true results errors [list System.Data.SQLite.dll Eagle.dll]]
          196  +
          197  +    set callbackResults [list]
          198  +
          199  +    list $code $results \
          200  +        [expr {[info exists errors] ? $errors : ""}] \
          201  +        [expr {$code eq "Ok" ? [catch {
          202  +          object invoke _Dynamic${id}.Test${id} BackupAndGetData "" $memSource
          203  +        } result] : [set result ""]}] $result $callbackResults
          204  +  } -cleanup {
          205  +    cleanupDb $fileName(2)
          206  +    cleanupDb $fileName(1) memDb
          207  +
          208  +    unset -nocomplain result results errors code index memSource dataSource \
          209  +        id memDb db fileName callbackResults
          210  +  } -constraints \
          211  +  {eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} \
          212  +-match regexp -result [appendArgs \
          213  +"^Ok System#CodeDom#Compiler#CompilerResults#\\d+ \\{\\} " \
          214  +[lindex $params(results) $i]]}
          215  +}
    97    216   
    98         -  list $code $results \
    99         -      [expr {[info exists errors] ? $errors : ""}] \
   100         -      [expr {$code eq "Ok" ? [catch {
   101         -        object invoke _Dynamic${id}.Test${id} GetRows $memSource
   102         -      } result] : [set result ""]}] $result
   103         -} -cleanup {
   104         -  cleanupDb $fileName(2)
   105         -  cleanupDb $fileName(1) memDb
          217  +###############################################################################
   106    218   
   107         -  unset -nocomplain result results errors code index memSource dataSource id \
   108         -      memDb db fileName
   109         -} -constraints \
   110         -{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} \
   111         --match regexp -result {^Ok System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0\
   112         -\{1 1048576 1048576 1048576 1048576 1048576 1048576 1048576 1048576 1048576\
   113         -1048576 10\}$}}
          219  +unset -nocomplain i params pages callback
   114    220   
   115    221   ###############################################################################
   116    222   
   117    223   runSQLiteTestEpilogue
   118    224   runTestEpilogue