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 Side-by-Side Diffs Ignore Whitespace Patch

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

     8      8   namespace System.Data.SQLite
     9      9   {
    10     10     using System;
    11     11     using System.Runtime.InteropServices;
    12     12     using System.Collections.Generic;
    13     13     using System.Globalization;
    14     14   
           15  +#if !PLATFORM_COMPACTFRAMEWORK
           16  +  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
           17  +#endif
           18  +  internal delegate void SQLiteLogCallback(IntPtr puser, int err_code, IntPtr message);
           19  +
    15     20     /// <summary>
    16     21     /// This class implements SQLiteBase completely, and is the guts of the code that interop's SQLite with .NET
    17     22     /// </summary>
    18     23     internal class SQLite3 : SQLiteBase
    19     24     {
    20     25       /// <summary>
    21     26       /// The opaque pointer returned to us by the sqlite provider

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

   203    203   
   204    204       internal long _version;
   205    205   
   206    206       private event SQLiteUpdateEventHandler _updateHandler;
   207    207       private event SQLiteCommitHandler _commitHandler;
   208    208       private event SQLiteTraceEventHandler _traceHandler;
   209    209       private event EventHandler _rollbackHandler;
   210         -    private event SQLiteLogEventHandler _logHandler;
   211    210   
   212    211       private SQLiteUpdateCallback _updateCallback;
   213    212       private SQLiteCommitCallback _commitCallback;
   214    213       private SQLiteTraceCallback _traceCallback;
   215    214       private SQLiteRollbackCallback _rollbackCallback;
   216         -    private SQLiteLogCallback _logCallback;
   217    215   
   218    216       /// <summary>
   219    217       /// This event is raised whenever the database is opened or closed.
   220    218       /// </summary>
   221    219       public override event StateChangeEventHandler StateChange;
   222    220   
   223    221       ///<overloads>
................................................................................
   811    809                                                                          FindKey(opts, "DateTimeFormat", "ISO8601"),
   812    810                                                                          true);
   813    811   
   814    812             if (bUTF16) // SQLite automatically sets the encoding of the database to UTF16 if called from sqlite3_open16()
   815    813               _sql = new SQLite3_UTF16(dateFormat);
   816    814             else
   817    815               _sql = new SQLite3(dateFormat);
   818         -
   819         -          if (_sql != null && _logHandler != null)
   820         -          {
   821         -              if (_logCallback == null) _logCallback = new SQLiteLogCallback(LogCallback);
   822         -              if (_logCallback != null) _sql.SetLogCallback(_logCallback);
   823         -          }
   824    816           }
   825    817   
   826    818           SQLiteOpenFlagsEnum flags = SQLiteOpenFlagsEnum.None;
   827    819   
   828    820           if (SQLiteConvert.ToBoolean(FindKey(opts, "FailIfMissing", Boolean.FalseString)) == false)
   829    821             flags |= SQLiteOpenFlagsEnum.Create;
   830    822   
................................................................................
  2347   2339       }
  2348   2340   
  2349   2341       private void RollbackCallback(IntPtr parg)
  2350   2342       {
  2351   2343         _rollbackHandler(this, EventArgs.Empty);
  2352   2344       }
  2353   2345   
  2354         -    /// <summary>
  2355         -    /// This event is raised whenever SQLite raises a logging event.
  2356         -    /// </summary>
  2357         -    public event SQLiteLogEventHandler Log
  2358         -    {
  2359         -        add
  2360         -        {
  2361         -            _logHandler += value;
  2362         -            // callback handler will be set/removed at open/close
  2363         -        }
  2364         -        remove
  2365         -        {
  2366         -            _logHandler -= value;
  2367         -            if (_logHandler==null)
  2368         -            {
  2369         -                _sql.SetLogCallback(null);
  2370         -                _logCallback = null;
  2371         -            }
  2372         -
  2373         -        }
  2374         -    }
  2375         -
  2376         -    private void LogCallback(IntPtr puser, int err_code, IntPtr message)
  2377         -    {
  2378         -        if (_logHandler != null) 
  2379         -            _logHandler(this, 
  2380         -                        new LogEventArgs(puser, 
  2381         -                                         err_code,
  2382         -                                         SQLiteBase.UTF8ToString(message, -1)));
  2383         -    }
  2384         -
  2385   2346     }
  2386   2347   
  2387   2348     /// <summary>
  2388   2349     /// The I/O file cache flushing behavior for the connection
  2389   2350     /// </summary>
  2390   2351     public enum SynchronizationModes
  2391   2352     {
................................................................................
  2419   2380     internal delegate void SQLiteTraceCallback(IntPtr puser, IntPtr statement);
  2420   2381   
  2421   2382   #if !PLATFORM_COMPACTFRAMEWORK
  2422   2383     [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  2423   2384   #endif
  2424   2385     internal delegate void SQLiteRollbackCallback(IntPtr puser);
  2425   2386   
  2426         -#if !PLATFORM_COMPACTFRAMEWORK
  2427         -  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  2428         -#endif
  2429         -  internal delegate void SQLiteLogCallback(IntPtr puser, int err_code, IntPtr message);
  2430         -
  2431   2387     /// <summary>
  2432   2388     /// Raised when a transaction is about to be committed.  To roll back a transaction, set the 
  2433   2389     /// rollbackTrans boolean value to true.
  2434   2390     /// </summary>
  2435   2391     /// <param name="sender">The connection committing the transaction</param>
  2436   2392     /// <param name="e">Event arguments on the transaction</param>
  2437   2393     public delegate void SQLiteCommitHandler(object sender, CommitEventArgs e);
................................................................................
  2443   2399     /// <param name="e">The event parameters which triggered the event</param>
  2444   2400     public delegate void SQLiteUpdateEventHandler(object sender, UpdateEventArgs e);
  2445   2401   
  2446   2402     /// <summary>
  2447   2403     /// Raised when a statement first begins executing on a given connection
  2448   2404     /// </summary>
  2449   2405     /// <param name="sender">The connection executing the statement</param>
  2450         -  /// <param name="e">Event arguments on the trace</param>
         2406  +  /// <param name="e">Event arguments of the trace</param>
  2451   2407     public delegate void SQLiteTraceEventHandler(object sender, TraceEventArgs e);
  2452   2408   
  2453         -  /// <summary>
  2454         -  /// Raised when a log event occurs.
  2455         -  /// </summary>
  2456         -  /// <param name="sender">The current connection</param>
  2457         -  /// <param name="e">Event arguments on the trace</param>
  2458         -  public delegate void SQLiteLogEventHandler(object sender, LogEventArgs e);
  2459         -
  2460   2409     /// <summary>
  2461   2410     /// Whenever an update event is triggered on a connection, this enum will indicate
  2462   2411     /// exactly what type of operation is being performed.
  2463   2412     /// </summary>
  2464   2413     public enum UpdateEventType
  2465   2414     {
  2466   2415       /// <summary>
................................................................................
  2539   2488   
  2540   2489       internal TraceEventArgs(string statement)
  2541   2490       {
  2542   2491         Statement = statement;
  2543   2492       }
  2544   2493     }
  2545   2494   
  2546         -  /// <summary>
  2547         -  /// Passed during an Log callback
  2548         -  /// </summary>
  2549         -  public class LogEventArgs : EventArgs
  2550         -  {
  2551         -      /// <summary>
  2552         -      /// The error code.
  2553         -      /// </summary>
  2554         -      public readonly int ErrorCode;
  2555         -
  2556         -      /// <summary>
  2557         -      /// SQL statement text as the statement first begins executing
  2558         -      /// </summary>
  2559         -      public readonly string Message;
  2560         -
  2561         -      internal LogEventArgs(IntPtr puser, int err_code, string message)
  2562         -      {
  2563         -          // puser should be NULL
  2564         -          ErrorCode = err_code;
  2565         -          Message = message;
  2566         -      }
  2567         -  }
  2568         -
  2569   2495   }

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

     5      5    * Released to the public domain, use at your own risk!
     6      6    ********************************************************/
     7      7   
     8      8   namespace System.Data.SQLite
     9      9   {
    10     10     using System;
    11     11     using System.Data.Common;
           12  +
           13  +  /// <summary>
           14  +  /// Passed during an Log callback
           15  +  /// </summary>
           16  +  public class LogEventArgs : EventArgs
           17  +  {
           18  +      /// <summary>
           19  +      /// The error code.
           20  +      /// </summary>
           21  +      public readonly int ErrorCode;
           22  +
           23  +      /// <summary>
           24  +      /// SQL statement text as the statement first begins executing
           25  +      /// </summary>
           26  +      public readonly string Message;
           27  +
           28  +      internal LogEventArgs(IntPtr puser, int err_code, string message)
           29  +      {
           30  +          // puser should be NULL
           31  +          ErrorCode = err_code;
           32  +          Message = message;
           33  +      }
           34  +  }
           35  +
           36  +  /// <summary>
           37  +  /// Raised when a log event occurs.
           38  +  /// </summary>
           39  +  /// <param name="sender">The current connection</param>
           40  +  /// <param name="e">Event arguments of the trace</param>
           41  +  public delegate void SQLiteLogEventHandler(object sender, LogEventArgs e);
           42  +
    12     43   
    13     44   #if !PLATFORM_COMPACTFRAMEWORK
    14     45     /// <summary>
    15     46     /// SQLite implementation of DbProviderFactory.
    16     47     /// </summary>
    17     48     public sealed partial class SQLiteFactory : DbProviderFactory
    18     49     {
           50  +    /// <summary>
           51  +    /// Member variable to store the application log handler to call.
           52  +    /// </summary>
           53  +    internal event SQLiteLogEventHandler _logHandler;
           54  +    /// <summary>
           55  +    /// The log callback passed to SQLite engine.
           56  +    /// </summary>
           57  +    private SQLiteLogCallback _logCallback;
           58  +    /// <summary>
           59  +    /// The base SQLite object to interop with.
           60  +    /// </summary>
           61  +    internal SQLiteBase _sql;
           62  +
           63  +    /// <summary>
           64  +    /// This event is raised whenever SQLite raises a logging event.
           65  +    /// Note that this should be set as one of the first things in the
           66  +    /// application.
           67  +    /// </summary>
           68  +    public event SQLiteLogEventHandler Log
           69  +    {
           70  +        add
           71  +        {
           72  +            // Remove any copies of this event handler from registered list.
           73  +            // This essentially means that a handler will be called only once
           74  +            // no matter how many times it is added.
           75  +            _logHandler -= value;
           76  +            // add this to the list of event handlers
           77  +            _logHandler += value;
           78  +        }
           79  +        remove
           80  +        {
           81  +            _logHandler -= value;
           82  +        }
           83  +    }
           84  +
           85  +    /// <summary>
           86  +    /// Internal proxy function that calls any registered application log
           87  +    /// event handlers.
           88  +    /// </summary>
           89  +    private void LogCallback(IntPtr puser, int err_code, IntPtr message)
           90  +    {
           91  +      // if there are any registered event handlers
           92  +      if (_logHandler != null)
           93  +        // call them
           94  +        _logHandler(this,
           95  +                    new LogEventArgs(puser,
           96  +                                     err_code,
           97  +                                     SQLiteBase.UTF8ToString(message, -1)));
           98  +    }
           99  +
          100  +    /// <overloads>
          101  +    /// Constructs a new SQLiteFactory object
          102  +    /// </overloads>
          103  +    /// <summary>
          104  +    /// Default constructor
          105  +    /// </summary>
          106  +    public SQLiteFactory()
          107  +    {
          108  +      if (_sql == null)
          109  +      {
          110  +        _sql = new SQLite3(SQLiteDateFormats.ISO8601);
          111  +        if (_sql != null)
          112  +        {
          113  +          // Create a single "global" callback to register with SQLite.
          114  +          // This callback will pass the event on to any registered
          115  +          // handler.  We only want to do this once.
          116  +          if (_logCallback == null)
          117  +          {
          118  +            _logCallback = new SQLiteLogCallback(LogCallback);
          119  +            if (_logCallback != null)
          120  +            {
          121  +              _sql.SetLogCallback(_logCallback);
          122  +            }
          123  +          }
          124  +        }
          125  +      }
          126  +    }
          127  +
    19    128       /// <summary>
    20    129       /// Static instance member which returns an instanced SQLiteFactory class.
    21    130       /// </summary>
    22    131       public static readonly SQLiteFactory Instance = new SQLiteFactory();
    23    132   
    24    133       /// <summary>
    25    134       /// Returns a new SQLiteCommand object.

Changes to test/TestCases.cs.

  1590   1590       [Test]
  1591   1591       internal void SetLogCallbackTest()
  1592   1592       {
  1593   1593           if (_fact.GetType().Name.IndexOf("SQLite", StringComparison.OrdinalIgnoreCase) > -1)
  1594   1594           {
  1595   1595               SQLiteConnection cnn = new SQLiteConnection(_cnnstring.ConnectionString);
  1596   1596   
  1597         -            cnn.Shutdown();  // we need to shutdown so that we can change config options
  1598         -
  1599   1597               // create and add a log event handler
  1600   1598               SQLiteLogEventHandler logHandler = new SQLiteLogEventHandler(OnLogEvent);
  1601         -            cnn.Log += logHandler;
         1599  +            SQLiteFactory sqlite_fact = (SQLiteFactory)_fact;
         1600  +
         1601  +            sqlite_fact.Log += logHandler;
  1602   1602   
  1603   1603               cnn.Open();
  1604   1604   
  1605   1605               logevents = 0;
  1606   1606   
  1607   1607               cnn.LogMessage(1, "test log event");
  1608   1608   
  1609   1609               if (logevents != 1)
  1610   1610                   throw new Exception("Log event count incorrect.");
  1611   1611   
  1612   1612               cnn.Close();
  1613   1613   
  1614         -            cnn.Shutdown();  // we need to shutdown so that we can change config options
  1615         -
  1616   1614               // remove the log handler before the connection is closed.
  1617         -            cnn.Log -= logHandler;
         1615  +            sqlite_fact.Log -= logHandler;
  1618   1616   
  1619   1617           }
  1620   1618       }
  1621   1619   
  1622   1620       /// <summary>
  1623   1621       /// Open a reader and then attempt to write to test the writer's command timeout property
  1624   1622       /// SQLite doesn't allow a write when a reader is active.