System.Data.SQLite

Check-in [5e6b70f411]
Login

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

Overview
Comment:Add threading test to the Windows CE test application. Also, some cleanup and refactoring work to make adding new tests easier.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 5e6b70f411677578f5d98ee80ebbd690d330dcc5
User & Date: mistachkin 2012-10-09 11:33:36.615
Context
2012-10-09
13:07
For Visual Studio 2012 only, run the design-time installer tool twice for both install and uninstall to make sure the settings are present in the per-user and per-machine registry hives. check-in: c1187b14fb user: mistachkin tags: trunk
11:33
Add threading test to the Windows CE test application. Also, some cleanup and refactoring work to make adding new tests easier. check-in: 5e6b70f411 user: mistachkin tags: trunk
09:40
Add wrapper batch file for the Windows CE test automation and update the version history docs. check-in: 305bd4b0ab user: mistachkin tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to testce/Program.cs.
14
15
16
17
18
19
20





21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

namespace test
{
  class Program
  {
    private static readonly string DefaultConnectionString =
        "Data Source={DataDirectory}\\test.db;Password=yVXL39etehPX;";






    [MTAThread]
    static int Main(string[] args)
    {
      bool autoClose = false;
      int exitCode = 2; /* INCOMPLETE */
      Assembly assembly = Assembly.GetExecutingAssembly();
      AssemblyName assemblyName = assembly.GetName();
      string directory = Path.GetDirectoryName(assemblyName.CodeBase);

      if (args.Length > 0)
          autoClose = bool.Parse(args[0]);

      try { File.Delete(directory + "\\test.db"); } catch { }

      SQLiteFunction.RegisterFunction(typeof(TestFunc));
      SQLiteFunction.RegisterFunction(typeof(MyCount));
      SQLiteFunction.RegisterFunction(typeof(MySequence));

      using (DbConnection cnn = new SQLiteConnection())
      {
        string connectionString = DefaultConnectionString;

        try
        {
          //
          // NOTE: Attempt to open the configuration file associated with







>
>
>
>
>



















|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

namespace test
{
  class Program
  {
    private static readonly string DefaultConnectionString =
        "Data Source={DataDirectory}\\test.db;Password=yVXL39etehPX;";

    internal static DbConnection NewConnection()
    {
        return new SQLiteConnection();
    }

    [MTAThread]
    static int Main(string[] args)
    {
      bool autoClose = false;
      int exitCode = 2; /* INCOMPLETE */
      Assembly assembly = Assembly.GetExecutingAssembly();
      AssemblyName assemblyName = assembly.GetName();
      string directory = Path.GetDirectoryName(assemblyName.CodeBase);

      if (args.Length > 0)
          autoClose = bool.Parse(args[0]);

      try { File.Delete(directory + "\\test.db"); } catch { }

      SQLiteFunction.RegisterFunction(typeof(TestFunc));
      SQLiteFunction.RegisterFunction(typeof(MyCount));
      SQLiteFunction.RegisterFunction(typeof(MySequence));

      using (DbConnection cnn = NewConnection())
      {
        string connectionString = DefaultConnectionString;

        try
        {
          //
          // NOTE: Attempt to open the configuration file associated with
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
          //
          connectionString = connectionString.Replace(
            "{DataDirectory}", directory);

          cnn.ConnectionString = connectionString;
          cnn.Open();

          TestCases tests = new TestCases(autoClose);

          tests.Run(cnn);

          Application.Run(tests.frm);

          if (tests.Succeeded())
              exitCode = 0; /* SUCCESS */
          else
              exitCode = 1; /* FAILURE */







|

|







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
          //
          connectionString = connectionString.Replace(
            "{DataDirectory}", directory);

          cnn.ConnectionString = connectionString;
          cnn.Open();

          TestCases tests = new TestCases(connectionString, cnn, autoClose);

          tests.Run();

          Application.Run(tests.frm);

          if (tests.Succeeded())
              exitCode = 0; /* SUCCESS */
          else
              exitCode = 1; /* FAILURE */
Changes to testce/TestCases.cs.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
/********************************************************
 * ADO.NET 2.0 Data Provider for SQLite Version 3.X
 * Written by Robert Simpson (robert@blackcastlesoft.com)
 * 
 * Released to the public domain, use at your own risk!
 ********************************************************/

using System;
using System.Data.Common;
using System.Data;
using System.Data.SQLite;


namespace test
{

  /// <summary>
  /// Scalar user-defined function.  In this example, the same class is declared twice with 
  /// different function names to demonstrate how to use alias names for user-defined functions.











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/********************************************************
 * ADO.NET 2.0 Data Provider for SQLite Version 3.X
 * Written by Robert Simpson (robert@blackcastlesoft.com)
 * 
 * Released to the public domain, use at your own risk!
 ********************************************************/

using System;
using System.Data.Common;
using System.Data;
using System.Data.SQLite;
using System.Threading;

namespace test
{

  /// <summary>
  /// Scalar user-defined function.  In this example, the same class is declared twice with 
  /// different function names to demonstrate how to use alias names for user-defined functions.
69
70
71
72
73
74
75


76
77
78
79
80
81




82


83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
    }
  }

  internal class TestCases
  {
    internal Form1 frm;



    private bool autoClose;
    private int total;
    private int passed;
    private int failed;

    internal TestCases(bool autoExit)




    {


        this.autoClose = autoExit;
    }

    internal bool Succeeded()
    {
        return (failed == 0) && (passed == total);
    }

    internal void Run(DbConnection cnn)
    {
      frm = new Form1();

      frm.Show();

      Type type = cnn.GetType();
      frm.WriteLine("\r\nBeginning Test on " + type.ToString());

      SQLiteConnection cnn2 = cnn as SQLiteConnection;
      if (cnn2 != null)







>
>





|
>
>
>
>

>
>








|


<







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

103
104
105
106
107
108
109
    }
  }

  internal class TestCases
  {
    internal Form1 frm;

    private string connectionString;
    private DbConnection cnn;
    private bool autoClose;
    private int total;
    private int passed;
    private int failed;

    internal TestCases(
        string connectionString,
        DbConnection cnn,
        bool autoExit
        )
    {
        this.connectionString = connectionString;
        this.cnn = cnn;
        this.autoClose = autoExit;
    }

    internal bool Succeeded()
    {
        return (failed == 0) && (passed == total);
    }

    internal void Run()
    {
      frm = new Form1();

      frm.Show();

      Type type = cnn.GetType();
      frm.WriteLine("\r\nBeginning Test on " + type.ToString());

      SQLiteConnection cnn2 = cnn as SQLiteConnection;
      if (cnn2 != null)
177
178
179
180
181
182
183




184
185
186
187
188
189
190
      try { UserAggregate(cnn); frm.WriteLine("SUCCESS - UserAggregate"); passed++; }
      catch (Exception) { frm.WriteLine("FAIL - UserAggregate"); failed++; }

      total++;
      try { UserCollation(cnn); frm.WriteLine("SUCCESS - UserCollation"); passed++; }
      catch (Exception) { frm.WriteLine("FAIL - UserCollation"); failed++; }





      total++;
      try { DropTable(cnn); frm.WriteLine("SUCCESS - DropTable"); passed++; }
      catch (Exception) { frm.WriteLine("FAIL - DropTable"); failed++; }

      frm.WriteLine("\r\nTests Finished.");
      frm.WriteLine(String.Format("\r\nCounts: {0} total, {1} passed, {2} failed", total, passed, failed));
      frm.WriteLine(String.Format("Result: {0}", Succeeded() ? "SUCCESS" : "FAILURE"));







>
>
>
>







185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
      try { UserAggregate(cnn); frm.WriteLine("SUCCESS - UserAggregate"); passed++; }
      catch (Exception) { frm.WriteLine("FAIL - UserAggregate"); failed++; }

      total++;
      try { UserCollation(cnn); frm.WriteLine("SUCCESS - UserCollation"); passed++; }
      catch (Exception) { frm.WriteLine("FAIL - UserCollation"); failed++; }

      total++;
      try { MultipleThreadStress(cnn); frm.WriteLine("SUCCESS - MultipleThreadStress"); passed++; }
      catch (Exception) { frm.WriteLine("FAIL - MultipleThreadStress"); failed++; }

      total++;
      try { DropTable(cnn); frm.WriteLine("SUCCESS - DropTable"); passed++; }
      catch (Exception) { frm.WriteLine("FAIL - DropTable"); failed++; }

      frm.WriteLine("\r\nTests Finished.");
      frm.WriteLine(String.Format("\r\nCounts: {0} total, {1} passed, {2} failed", total, passed, failed));
      frm.WriteLine(String.Format("Result: {0}", Succeeded() ? "SUCCESS" : "FAILURE"));
404
405
406
407
408
409
410





411
412
413
414

415
416
417
418
419
420
421
        //cmd.CommandText = "CREATE TABLE TestCase (ID bigint primary key identity, Field1 Integer, Field2 Float, Field3 VARCHAR(50), Field4 CHAR(10), Field5 DateTime, Field6 Image)";
        cmd.ExecuteNonQuery();
      }
    }

    internal void DropTable(DbConnection cnn)
    {





      using (DbCommand cmd = cnn.CreateCommand())
      {
        cmd.CommandText = "DROP TABLE TestCase";
        cmd.ExecuteNonQuery();

      }
    }

    internal void InsertTable(DbConnection cnn)
    {
      using (DbCommand cmd = cnn.CreateCommand())
      {







>
>
>
>
>
|
|
|
|
>







416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
        //cmd.CommandText = "CREATE TABLE TestCase (ID bigint primary key identity, Field1 Integer, Field2 Float, Field3 VARCHAR(50), Field4 CHAR(10), Field5 DateTime, Field6 Image)";
        cmd.ExecuteNonQuery();
      }
    }

    internal void DropTable(DbConnection cnn)
    {
      string[] tables = {
        "TestCase", "keyinfotest", "datatypetest", "TestThreads"
      };
      foreach (string table in tables)
      {
        using (DbCommand cmd = cnn.CreateCommand())
        {
          cmd.CommandText = String.Format("DROP TABLE {0};", table);
          cmd.ExecuteNonQuery();
        }
      }
    }

    internal void InsertTable(DbConnection cnn)
    {
      using (DbCommand cmd = cnn.CreateCommand())
      {
876
877
878
879
880
881
882
883




884




































































































        // and "Field3" will be next, followed by a NULL.  Our user-defined collating sequence will 
        // deliberately place them out of order so Field3 is first.
        cmd.CommandText = "SELECT Field3 FROM TestCase ORDER BY Field3 COLLATE MYSEQUENCE DESC";
        string s = (string)cmd.ExecuteScalar();
        if (s != "Field3") throw new ArgumentOutOfRangeException("MySequence didn't sort properly");
      }
    }
  }




}











































































































|
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
        // and "Field3" will be next, followed by a NULL.  Our user-defined collating sequence will 
        // deliberately place them out of order so Field3 is first.
        cmd.CommandText = "SELECT Field3 FROM TestCase ORDER BY Field3 COLLATE MYSEQUENCE DESC";
        string s = (string)cmd.ExecuteScalar();
        if (s != "Field3") throw new ArgumentOutOfRangeException("MySequence didn't sort properly");
      }
    }

    private int nextId = 0;
    private const int MAX_THREADS = 3;
    private const int MAX_ITERATIONS = 100;
    private ManualResetEvent goEvent = new ManualResetEvent(false);

    private static int GetThreadId()
    {
        return Thread.CurrentThread.ManagedThreadId;
    }

    // Mutli-threading test.
    internal void MultipleThreadStress(DbConnection cnn)
    {
        string[] commands = {
            "CREATE TABLE TestThreads(Id INTEGER PRIMARY KEY, Data INTEGER);",
            "INSERT INTO TestThreads (Id, Data) VALUES (" +
                Interlocked.Increment(ref nextId).ToString() + ", " +
                GetThreadId().ToString() + ");"
        };

        foreach (string command in commands)
        {
            using (DbCommand cmd = cnn.CreateCommand())
            {
                cmd.CommandText = command;
                cmd.ExecuteNonQuery();
            }
        }

        Thread[] threads = new Thread[MAX_THREADS];

        for (int index = 0; index < threads.Length; index++)
            threads[index] = new Thread(TestThreadStart);

        for (int index = 0; index < threads.Length; index++)
            threads[index].Start();

        goEvent.Set(); /* GO */

        for (int index = 0; index < threads.Length; index++)
            threads[index].Join();

        int count;

        using (DbCommand cmd = cnn.CreateCommand())
        {
            cmd.CommandText = "SELECT COUNT(*) FROM TestThreads;";
            object value = cmd.ExecuteScalar();
            count = (value is int) ? (int)value : 0;
        }

        if ((count >= MAX_THREADS) &&
            (count <= (MAX_THREADS * MAX_ITERATIONS)))
        {
            throw new ArgumentOutOfRangeException("Unexpected thread count");
        }
    }

    private void TestThreadStart()
    {
        goEvent.WaitOne();

        using (DbConnection cnn = Program.NewConnection())
        {
            Random random = new Random();

            cnn.ConnectionString = this.connectionString;
            cnn.Open();

            for (int index = 0; index < MAX_ITERATIONS; index++)
            {
                try
                {
                    using (DbTransaction trans = cnn.BeginTransaction())
                    {
                        string[] commands = {
                            "INSERT INTO TestThreads (Id, Data) VALUES (" +
                                Interlocked.Increment(ref nextId).ToString() + ", " +
                                GetThreadId().ToString() + ");"
                        };

                        foreach (string command in commands)
                        {
                            using (DbCommand cmd = cnn.CreateCommand())
                            {
                                cmd.CommandText = command;
                                cmd.ExecuteNonQuery();
                            }
                        }

                        if ((index > 0) && (random.Next() % 2 == 0))
                            throw new Exception("test exception");

                        trans.Commit();
                    }
                }
                catch
                {
                    // do nothing.
                }
            }
        }
    }
  }
}