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 Show Whitespace Changes 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 {
           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 {
    24     78     setupDb [set fileName(1) :memory:] "" "" "" "" "" false memDb
    25         -  setupDb [set fileName(2) backup-1.1.db]
           79  +    setupDb [set fileName(2) [appendArgs backup-1. $i .db]]
    26     80   } -body {
    27     81     set id [object invoke Interpreter.GetActive NextId]
    28     82     set dataSource [file join [getDatabaseDirectory] $fileName(2)]
    29     83   
    30     84     sql execute $memDb {
    31     85       CREATE TABLE t1(x TEXT);
    32     86     }
................................................................................
    39     93   
    40     94     set memSource [object invoke -flags +NonPublic -objectflags +NoDispose \
    41     95         Interpreter.GetActive.connections get_Item $memDb]
    42     96   
    43     97     unset -nocomplain results errors
    44     98   
    45     99     set code [compileCSharpWith [subst {
          100  +      using System;
    46    101       using System.Data.SQLite;
    47    102       using System.Text;
          103  +      using Eagle._Components.Public;
    48    104   
    49    105       namespace _Dynamic${id}
    50    106       {
    51         -      public class Test${id}
          107  +        public static class Test${id}
          108  +        {
          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  +            )
    52    124         {
    53         -        public static string GetRows(
          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,
    54    138             SQLiteConnection source
    55    139             )
    56    140           {
    57    141             using (SQLiteConnection destination = new SQLiteConnection(
    58    142                 "Data Source=${dataSource};"))
    59    143             {
    60    144               destination.Open();
    61         -            source.BackupDatabase(destination, "main", "main", -1, null, 0);
          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);
    62    161   
    63    162               using (SQLiteCommand command = new SQLiteCommand(
    64    163                   "SELECT length(x) FROM t1;", destination))
    65    164               {
    66    165                 using (SQLiteDataReader dataReader = command.ExecuteReader())
    67    166                 {
    68         -                int rowCount = 0;
    69    167                   StringBuilder builder = new StringBuilder();
          168  +                  int rowCount = 0;
    70    169   
    71    170                   builder.Append(dataReader.FieldCount);
    72    171                   builder.Append(' ');
    73    172   
    74    173                   while (dataReader.Read())
    75    174                   {
    76    175                     builder.Append(dataReader.GetInt64(0));
................................................................................
    81    180                   builder.Append(rowCount);
    82    181                   return builder.ToString();
    83    182                 }
    84    183               }
    85    184             }
    86    185           }
    87    186   
    88         -        ///////////////////////////////////////////////////////////////////////
          187  +          /////////////////////////////////////////////////////////////////////
    89    188   
    90    189           public static void Main()
    91    190           {
    92    191             // do nothing.
    93    192           }
    94    193         }
    95    194       }
    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]
    97    198   
    98    199     list $code $results \
    99    200         [expr {[info exists errors] ? $errors : ""}] \
   100    201         [expr {$code eq "Ok" ? [catch {
   101         -        object invoke _Dynamic${id}.Test${id} GetRows $memSource
   102         -      } result] : [set result ""]}] $result
          202  +          object invoke _Dynamic${id}.Test${id} BackupAndGetData "" $memSource
          203  +        } result] : [set result ""]}] $result $callbackResults
   103    204   } -cleanup {
   104    205     cleanupDb $fileName(2)
   105    206     cleanupDb $fileName(1) memDb
   106    207   
   107         -  unset -nocomplain result results errors code index memSource dataSource id \
   108         -      memDb db fileName
          208  +    unset -nocomplain result results errors code index memSource dataSource \
          209  +        id memDb db fileName callbackResults
   109    210   } -constraints \
   110    211   {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\}$}}
          212  +-match regexp -result [appendArgs \
          213  +"^Ok System#CodeDom#Compiler#CompilerResults#\\d+ \\{\\} " \
          214  +[lindex $params(results) $i]]}
          215  +}
          216  +
          217  +###############################################################################
          218  +
          219  +unset -nocomplain i params pages callback
   114    220   
   115    221   ###############################################################################
   116    222   
   117    223   runSQLiteTestEpilogue
   118    224   runTestEpilogue