System.Data.SQLite
Check-in [c520cba472]
Not logged in

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

Overview
Comment:Moved log handler from SQLiteConnection object to SQLiteFactory object to prevent if from being prematurely GCed.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c520cba472cb750ff16917bce994b4ce5f13fa85
User & Date: shaneh 2011-05-23 04:12:28
Context
2011-05-24
01:17
Correct System.Data.SQLite.Linq version and resource information. Fix for [6489c5a396] and [133daf50d6]. check-in: 9ce4a2e044 user: shaneh tags: trunk
2011-05-23
04:12
Moved log handler from SQLiteConnection object to SQLiteFactory object to prevent if from being prematurely GCed. check-in: c520cba472 user: shaneh tags: trunk
04:07
Updated method for flagging test cases that are SQLite specific. check-in: 9525e5cf45 user: shaneh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

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

8
9
10
11
12
13
14





15
16
17
18
19
20
21
namespace System.Data.SQLite
{
  using System;
  using System.Runtime.InteropServices;
  using System.Collections.Generic;
  using System.Globalization;






  /// <summary>
  /// This class implements SQLiteBase completely, and is the guts of the code that interop's SQLite with .NET
  /// </summary>
  internal class SQLite3 : SQLiteBase
  {
    /// <summary>
    /// The opaque pointer returned to us by the sqlite provider







>
>
>
>
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
namespace System.Data.SQLite
{
  using System;
  using System.Runtime.InteropServices;
  using System.Collections.Generic;
  using System.Globalization;

#if !PLATFORM_COMPACTFRAMEWORK
  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
#endif
  internal delegate void SQLiteLogCallback(IntPtr puser, int err_code, IntPtr message);

  /// <summary>
  /// This class implements SQLiteBase completely, and is the guts of the code that interop's SQLite with .NET
  /// </summary>
  internal class SQLite3 : SQLiteBase
  {
    /// <summary>
    /// The opaque pointer returned to us by the sqlite provider

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

203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
...
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
....
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
....
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
....
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
....
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569

    internal long _version;

    private event SQLiteUpdateEventHandler _updateHandler;
    private event SQLiteCommitHandler _commitHandler;
    private event SQLiteTraceEventHandler _traceHandler;
    private event EventHandler _rollbackHandler;
    private event SQLiteLogEventHandler _logHandler;

    private SQLiteUpdateCallback _updateCallback;
    private SQLiteCommitCallback _commitCallback;
    private SQLiteTraceCallback _traceCallback;
    private SQLiteRollbackCallback _rollbackCallback;
    private SQLiteLogCallback _logCallback;

    /// <summary>
    /// This event is raised whenever the database is opened or closed.
    /// </summary>
    public override event StateChangeEventHandler StateChange;

    ///<overloads>
................................................................................
                                                                       FindKey(opts, "DateTimeFormat", "ISO8601"),
                                                                       true);

          if (bUTF16) // SQLite automatically sets the encoding of the database to UTF16 if called from sqlite3_open16()
            _sql = new SQLite3_UTF16(dateFormat);
          else
            _sql = new SQLite3(dateFormat);

          if (_sql != null && _logHandler != null)
          {
              if (_logCallback == null) _logCallback = new SQLiteLogCallback(LogCallback);
              if (_logCallback != null) _sql.SetLogCallback(_logCallback);
          }
        }

        SQLiteOpenFlagsEnum flags = SQLiteOpenFlagsEnum.None;

        if (SQLiteConvert.ToBoolean(FindKey(opts, "FailIfMissing", Boolean.FalseString)) == false)
          flags |= SQLiteOpenFlagsEnum.Create;

................................................................................
    }

    private void RollbackCallback(IntPtr parg)
    {
      _rollbackHandler(this, EventArgs.Empty);
    }

    /// <summary>
    /// This event is raised whenever SQLite raises a logging event.
    /// </summary>
    public event SQLiteLogEventHandler Log
    {
        add
        {
            _logHandler += value;
            // callback handler will be set/removed at open/close
        }
        remove
        {
            _logHandler -= value;
            if (_logHandler==null)
            {
                _sql.SetLogCallback(null);
                _logCallback = null;
            }

        }
    }

    private void LogCallback(IntPtr puser, int err_code, IntPtr message)
    {
        if (_logHandler != null) 
            _logHandler(this, 
                        new LogEventArgs(puser, 
                                         err_code,
                                         SQLiteBase.UTF8ToString(message, -1)));
    }

  }

  /// <summary>
  /// The I/O file cache flushing behavior for the connection
  /// </summary>
  public enum SynchronizationModes
  {
................................................................................
  internal delegate void SQLiteTraceCallback(IntPtr puser, IntPtr statement);

#if !PLATFORM_COMPACTFRAMEWORK
  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
#endif
  internal delegate void SQLiteRollbackCallback(IntPtr puser);

#if !PLATFORM_COMPACTFRAMEWORK
  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
#endif
  internal delegate void SQLiteLogCallback(IntPtr puser, int err_code, IntPtr message);

  /// <summary>
  /// Raised when a transaction is about to be committed.  To roll back a transaction, set the 
  /// rollbackTrans boolean value to true.
  /// </summary>
  /// <param name="sender">The connection committing the transaction</param>
  /// <param name="e">Event arguments on the transaction</param>
  public delegate void SQLiteCommitHandler(object sender, CommitEventArgs e);
................................................................................
  /// <param name="e">The event parameters which triggered the event</param>
  public delegate void SQLiteUpdateEventHandler(object sender, UpdateEventArgs e);

  /// <summary>
  /// Raised when a statement first begins executing on a given connection
  /// </summary>
  /// <param name="sender">The connection executing the statement</param>
  /// <param name="e">Event arguments on the trace</param>
  public delegate void SQLiteTraceEventHandler(object sender, TraceEventArgs e);

  /// <summary>
  /// Raised when a log event occurs.
  /// </summary>
  /// <param name="sender">The current connection</param>
  /// <param name="e">Event arguments on the trace</param>
  public delegate void SQLiteLogEventHandler(object sender, LogEventArgs e);

  /// <summary>
  /// Whenever an update event is triggered on a connection, this enum will indicate
  /// exactly what type of operation is being performed.
  /// </summary>
  public enum UpdateEventType
  {
    /// <summary>
................................................................................

    internal TraceEventArgs(string statement)
    {
      Statement = statement;
    }
  }

  /// <summary>
  /// Passed during an Log callback
  /// </summary>
  public class LogEventArgs : EventArgs
  {
      /// <summary>
      /// The error code.
      /// </summary>
      public readonly int ErrorCode;

      /// <summary>
      /// SQL statement text as the statement first begins executing
      /// </summary>
      public readonly string Message;

      internal LogEventArgs(IntPtr puser, int err_code, string message)
      {
          // puser should be NULL
          ErrorCode = err_code;
          Message = message;
      }
  }

}







<





<







 







<
<
<
<
<
<







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







<
<
<
<
<







 







|


<
<
<
<
<
<
<







 







<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
203
204
205
206
207
208
209

210
211
212
213
214

215
216
217
218
219
220
221
...
809
810
811
812
813
814
815






816
817
818
819
820
821
822
....
2339
2340
2341
2342
2343
2344
2345































2346
2347
2348
2349
2350
2351
2352
....
2380
2381
2382
2383
2384
2385
2386





2387
2388
2389
2390
2391
2392
2393
....
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408







2409
2410
2411
2412
2413
2414
2415
....
2488
2489
2490
2491
2492
2493
2494









2495















    internal long _version;

    private event SQLiteUpdateEventHandler _updateHandler;
    private event SQLiteCommitHandler _commitHandler;
    private event SQLiteTraceEventHandler _traceHandler;
    private event EventHandler _rollbackHandler;


    private SQLiteUpdateCallback _updateCallback;
    private SQLiteCommitCallback _commitCallback;
    private SQLiteTraceCallback _traceCallback;
    private SQLiteRollbackCallback _rollbackCallback;


    /// <summary>
    /// This event is raised whenever the database is opened or closed.
    /// </summary>
    public override event StateChangeEventHandler StateChange;

    ///<overloads>
................................................................................
                                                                       FindKey(opts, "DateTimeFormat", "ISO8601"),
                                                                       true);

          if (bUTF16) // SQLite automatically sets the encoding of the database to UTF16 if called from sqlite3_open16()
            _sql = new SQLite3_UTF16(dateFormat);
          else
            _sql = new SQLite3(dateFormat);






        }

        SQLiteOpenFlagsEnum flags = SQLiteOpenFlagsEnum.None;

        if (SQLiteConvert.ToBoolean(FindKey(opts, "FailIfMissing", Boolean.FalseString)) == false)
          flags |= SQLiteOpenFlagsEnum.Create;

................................................................................
    }

    private void RollbackCallback(IntPtr parg)
    {
      _rollbackHandler(this, EventArgs.Empty);
    }
































  }

  /// <summary>
  /// The I/O file cache flushing behavior for the connection
  /// </summary>
  public enum SynchronizationModes
  {
................................................................................
  internal delegate void SQLiteTraceCallback(IntPtr puser, IntPtr statement);

#if !PLATFORM_COMPACTFRAMEWORK
  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
#endif
  internal delegate void SQLiteRollbackCallback(IntPtr puser);






  /// <summary>
  /// Raised when a transaction is about to be committed.  To roll back a transaction, set the 
  /// rollbackTrans boolean value to true.
  /// </summary>
  /// <param name="sender">The connection committing the transaction</param>
  /// <param name="e">Event arguments on the transaction</param>
  public delegate void SQLiteCommitHandler(object sender, CommitEventArgs e);
................................................................................
  /// <param name="e">The event parameters which triggered the event</param>
  public delegate void SQLiteUpdateEventHandler(object sender, UpdateEventArgs e);

  /// <summary>
  /// Raised when a statement first begins executing on a given connection
  /// </summary>
  /// <param name="sender">The connection executing the statement</param>
  /// <param name="e">Event arguments of the trace</param>
  public delegate void SQLiteTraceEventHandler(object sender, TraceEventArgs e);








  /// <summary>
  /// Whenever an update event is triggered on a connection, this enum will indicate
  /// exactly what type of operation is being performed.
  /// </summary>
  public enum UpdateEventType
  {
    /// <summary>
................................................................................

    internal TraceEventArgs(string statement)
    {
      Statement = statement;
    }
  }










}














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

5
6
7
8
9
10
11
12































13
14
15
16
17
18














































































19
20
21
22
23
24
25
 * Released to the public domain, use at your own risk!
 ********************************************************/

namespace System.Data.SQLite
{
  using System;
  using System.Data.Common;
































#if !PLATFORM_COMPACTFRAMEWORK
  /// <summary>
  /// SQLite implementation of DbProviderFactory.
  /// </summary>
  public sealed partial class SQLiteFactory : DbProviderFactory
  {














































































    /// <summary>
    /// Static instance member which returns an instanced SQLiteFactory class.
    /// </summary>
    public static readonly SQLiteFactory Instance = new SQLiteFactory();

    /// <summary>
    /// Returns a new SQLiteCommand object.







|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







5
6
7
8
9
10
11
12
13
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
 * Released to the public domain, use at your own risk!
 ********************************************************/

namespace System.Data.SQLite
{
  using System;
  using System.Data.Common;

  /// <summary>
  /// Passed during an Log callback
  /// </summary>
  public class LogEventArgs : EventArgs
  {
      /// <summary>
      /// The error code.
      /// </summary>
      public readonly int ErrorCode;

      /// <summary>
      /// SQL statement text as the statement first begins executing
      /// </summary>
      public readonly string Message;

      internal LogEventArgs(IntPtr puser, int err_code, string message)
      {
          // puser should be NULL
          ErrorCode = err_code;
          Message = message;
      }
  }

  /// <summary>
  /// Raised when a log event occurs.
  /// </summary>
  /// <param name="sender">The current connection</param>
  /// <param name="e">Event arguments of the trace</param>
  public delegate void SQLiteLogEventHandler(object sender, LogEventArgs e);


#if !PLATFORM_COMPACTFRAMEWORK
  /// <summary>
  /// SQLite implementation of DbProviderFactory.
  /// </summary>
  public sealed partial class SQLiteFactory : DbProviderFactory
  {
    /// <summary>
    /// Member variable to store the application log handler to call.
    /// </summary>
    internal event SQLiteLogEventHandler _logHandler;
    /// <summary>
    /// The log callback passed to SQLite engine.
    /// </summary>
    private SQLiteLogCallback _logCallback;
    /// <summary>
    /// The base SQLite object to interop with.
    /// </summary>
    internal SQLiteBase _sql;

    /// <summary>
    /// This event is raised whenever SQLite raises a logging event.
    /// Note that this should be set as one of the first things in the
    /// application.
    /// </summary>
    public event SQLiteLogEventHandler Log
    {
        add
        {
            // Remove any copies of this event handler from registered list.
            // This essentially means that a handler will be called only once
            // no matter how many times it is added.
            _logHandler -= value;
            // add this to the list of event handlers
            _logHandler += value;
        }
        remove
        {
            _logHandler -= value;
        }
    }

    /// <summary>
    /// Internal proxy function that calls any registered application log
    /// event handlers.
    /// </summary>
    private void LogCallback(IntPtr puser, int err_code, IntPtr message)
    {
      // if there are any registered event handlers
      if (_logHandler != null)
        // call them
        _logHandler(this,
                    new LogEventArgs(puser,
                                     err_code,
                                     SQLiteBase.UTF8ToString(message, -1)));
    }

    /// <overloads>
    /// Constructs a new SQLiteFactory object
    /// </overloads>
    /// <summary>
    /// Default constructor
    /// </summary>
    public SQLiteFactory()
    {
      if (_sql == null)
      {
        _sql = new SQLite3(SQLiteDateFormats.ISO8601);
        if (_sql != null)
        {
          // Create a single "global" callback to register with SQLite.
          // This callback will pass the event on to any registered
          // handler.  We only want to do this once.
          if (_logCallback == null)
          {
            _logCallback = new SQLiteLogCallback(LogCallback);
            if (_logCallback != null)
            {
              _sql.SetLogCallback(_logCallback);
            }
          }
        }
      }
    }

    /// <summary>
    /// Static instance member which returns an instanced SQLiteFactory class.
    /// </summary>
    public static readonly SQLiteFactory Instance = new SQLiteFactory();

    /// <summary>
    /// Returns a new SQLiteCommand object.

Changes to test/TestCases.cs.

1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600


1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
    [Test]
    internal void SetLogCallbackTest()
    {
        if (_fact.GetType().Name.IndexOf("SQLite", StringComparison.OrdinalIgnoreCase) > -1)
        {
            SQLiteConnection cnn = new SQLiteConnection(_cnnstring.ConnectionString);

            cnn.Shutdown();  // we need to shutdown so that we can change config options

            // create and add a log event handler
            SQLiteLogEventHandler logHandler = new SQLiteLogEventHandler(OnLogEvent);


            cnn.Log += logHandler;

            cnn.Open();

            logevents = 0;

            cnn.LogMessage(1, "test log event");

            if (logevents != 1)
                throw new Exception("Log event count incorrect.");

            cnn.Close();

            cnn.Shutdown();  // we need to shutdown so that we can change config options

            // remove the log handler before the connection is closed.
            cnn.Log -= logHandler;

        }
    }

    /// <summary>
    /// Open a reader and then attempt to write to test the writer's command timeout property
    /// SQLite doesn't allow a write when a reader is active.







<
<


>
>
|












<
<

|







1590
1591
1592
1593
1594
1595
1596


1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613


1614
1615
1616
1617
1618
1619
1620
1621
1622
    [Test]
    internal void SetLogCallbackTest()
    {
        if (_fact.GetType().Name.IndexOf("SQLite", StringComparison.OrdinalIgnoreCase) > -1)
        {
            SQLiteConnection cnn = new SQLiteConnection(_cnnstring.ConnectionString);



            // create and add a log event handler
            SQLiteLogEventHandler logHandler = new SQLiteLogEventHandler(OnLogEvent);
            SQLiteFactory sqlite_fact = (SQLiteFactory)_fact;

            sqlite_fact.Log += logHandler;

            cnn.Open();

            logevents = 0;

            cnn.LogMessage(1, "test log event");

            if (logevents != 1)
                throw new Exception("Log event count incorrect.");

            cnn.Close();



            // remove the log handler before the connection is closed.
            sqlite_fact.Log -= logHandler;

        }
    }

    /// <summary>
    /// Open a reader and then attempt to write to test the writer's command timeout property
    /// SQLite doesn't allow a write when a reader is active.