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

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

Overview
Comment:Allow monitoring of the creation of all critical handle derived class instances.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | onChanged
Files: files | file ages | folders
SHA1: b194408bb59533953ea5941d3722192b0d7887cf
User & Date: mistachkin 2013-09-04 03:42:25
Context
2013-09-04
04:24
Merge updates from trunk. check-in: 4a97ad717d user: mistachkin tags: onChanged
03:42
Allow monitoring of the creation of all critical handle derived class instances. check-in: b194408bb5 user: mistachkin tags: onChanged
2013-08-29
23:00
Raise the static OnChanged event for the connection when a data reader is created. check-in: 85f27cc9f8 user: mistachkin tags: onChanged
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

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

   122    122           )
   123    123         : base(fmt, kind, fmtString)
   124    124       {
   125    125           if (db != IntPtr.Zero)
   126    126           {
   127    127               _sql = new SQLiteConnectionHandle(db, ownHandle);
   128    128               _fileName = fileName;
          129  +
          130  +            SQLiteConnection.OnChanged(null, new ConnectionEventArgs(
          131  +                SQLiteConnectionEventType.NewCriticalHandle, null, null,
          132  +                null, null, _sql, fileName, new object[] { fmt, kind,
          133  +                fmtString, db, fileName, ownHandle }));
   129    134           }
   130    135       }
   131    136   
   132    137       ///////////////////////////////////////////////////////////////////////////////////////////////
   133    138   
   134    139       #region IDisposable "Pattern" Members
   135    140       private bool disposed;
................................................................................
   533    538             Trace.WriteLine(String.Format("Open: {0}", db));
   534    539   #endif
   535    540   
   536    541             if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, null);
   537    542             _sql = new SQLiteConnectionHandle(db, true);
   538    543           }
   539    544           lock (_sql) { /* HACK: Force the SyncBlock to be "created" now. */ }
          545  +
          546  +        SQLiteConnection.OnChanged(null, new ConnectionEventArgs(
          547  +            SQLiteConnectionEventType.NewCriticalHandle, null, null,
          548  +            null, null, _sql, strFilename, new object[] { strFilename,
          549  +            connectionFlags, openFlags, maxPoolSize, usePool }));
   540    550         }
   541    551   
   542    552         // Bind functions to this connection.  If any previous functions of the same name
   543    553         // were already bound, then the new bindings replace the old.
   544    554         if ((connectionFlags & SQLiteConnectionFlags.NoBindFunctions) != SQLiteConnectionFlags.NoBindFunctions)
   545    555         {
   546    556             if (_functions == null)
................................................................................
   739    749   #endif
   740    750   
   741    751   #if !NET_COMPACT_20 && TRACE_STATEMENT
   742    752               Trace.WriteLine(String.Format("Prepare ({0}): {1}", n, stmt));
   743    753   #endif
   744    754   
   745    755               if ((n == SQLiteErrorCode.Ok) && (stmt != IntPtr.Zero))
          756  +            {
          757  +              if (statementHandle != null) statementHandle.Dispose();
   746    758                 statementHandle = new SQLiteStatementHandle(_sql, stmt);
          759  +            }
          760  +          }
          761  +
          762  +          if (statementHandle != null)
          763  +          {
          764  +            SQLiteConnection.OnChanged(null, new ConnectionEventArgs(
          765  +              SQLiteConnectionEventType.NewCriticalHandle, null, null,
          766  +              null, null, statementHandle, strSql, new object[] { cnn,
          767  +              strSql, previous, timeoutMS }));
   747    768             }
   748    769   
   749    770             if (n == SQLiteErrorCode.Schema)
   750    771               retries++;
   751    772             else if (n == SQLiteErrorCode.Error)
   752    773             {
   753    774               if (String.Compare(GetLastError(), "near \"TYPES\": syntax error", StringComparison.OrdinalIgnoreCase) == 0)
................................................................................
  2103   2124                       throw new SQLiteException(resultCode, GetLastError());
  2104   2125                   else
  2105   2126                       throw new SQLiteException("failed to initialize backup");
  2106   2127               }
  2107   2128   
  2108   2129               backupHandle = new SQLiteBackupHandle(destHandle, backup);
  2109   2130           }
         2131  +
         2132  +        SQLiteConnection.OnChanged(null, new ConnectionEventArgs(
         2133  +            SQLiteConnectionEventType.NewCriticalHandle, null, null,
         2134  +            null, null, backupHandle, null, new object[] { destCnn,
         2135  +            destName, sourceName }));
  2110   2136   
  2111   2137           return new SQLiteBackup(
  2112   2138               this, backupHandle, destHandle, zDestName, sourceHandle,
  2113   2139               zSourceName);
  2114   2140       }
  2115   2141   
  2116   2142       /// <summary>

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

   192    192             Trace.WriteLine(String.Format("Open16: {0}", db));
   193    193   #endif
   194    194   
   195    195             if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, null);
   196    196             _sql = new SQLiteConnectionHandle(db, true);
   197    197           }
   198    198           lock (_sql) { /* HACK: Force the SyncBlock to be "created" now. */ }
          199  +
          200  +        SQLiteConnection.OnChanged(null, new ConnectionEventArgs(
          201  +            SQLiteConnectionEventType.NewCriticalHandle, null, null,
          202  +            null, null, _sql, strFilename, new object[] { strFilename,
          203  +            connectionFlags, openFlags, maxPoolSize, usePool }));
   199    204         }
   200    205   
   201    206         // Bind functions to this connection.  If any previous functions of the same name
   202    207         // were already bound, then the new bindings replace the old.
   203    208         if ((connectionFlags & SQLiteConnectionFlags.NoBindFunctions) != SQLiteConnectionFlags.NoBindFunctions)
   204    209         {
   205    210             if (_functions == null)

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

   147    147           _commandTimeout = connection.DefaultTimeout;
   148    148         }
   149    149   
   150    150         if (transaction != null)
   151    151           Transaction = transaction;
   152    152   
   153    153         SQLiteConnection.OnChanged(connection, new ConnectionEventArgs(
   154         -          SQLiteConnectionEventType.NewCommand, null, transaction, this, null, null));
          154  +          SQLiteConnectionEventType.NewCommand, null, transaction, this,
          155  +          null, null, null, null));
   155    156       }
   156    157   
   157    158       ///////////////////////////////////////////////////////////////////////////////////////////////
   158    159   
   159    160       [Conditional("CHECK_STATE")]
   160    161       internal static void Check(SQLiteCommand command)
   161    162       {

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

    41     41         public readonly IDbTransaction Transaction;
    42     42   
    43     43         /// <summary>
    44     44         /// The command associated with this event, if any.
    45     45         /// </summary>
    46     46         public readonly IDbCommand Command;
    47     47   
           48  +      /// <summary>
           49  +      /// The data reader associated with this event, if any.
           50  +      /// </summary>
           51  +      public readonly IDataReader DataReader;
           52  +
           53  +      /// <summary>
           54  +      /// The critical handle associated with this event, if any.
           55  +      /// </summary>
           56  +      public readonly CriticalHandle CriticalHandle;
           57  +
    48     58         /// <summary>
    49     59         /// Command or message text associated with this event, if any.
    50     60         /// </summary>
    51     61         public readonly string Text;
    52     62   
    53     63         /// <summary>
    54     64         /// Extra data associated with this event, if any.
................................................................................
    59     69         /// Constructs the object.
    60     70         /// </summary>
    61     71         /// <param name="eventType">The type of event being raised.</param>
    62     72         /// <param name="eventArgs">The base <see cref="EventArgs" /> associated
    63     73         /// with this event, if any.</param>
    64     74         /// <param name="transaction">The transaction associated with this event, if any.</param>
    65     75         /// <param name="command">The command associated with this event, if any.</param>
           76  +      /// <param name="dataReader">The data reader associated with this event, if any.</param>
           77  +      /// <param name="criticalHandle">The critical handle associated with this event, if any.</param>
    66     78         /// <param name="text">The command or message text, if any.</param>
    67     79         /// <param name="data">The extra data, if any.</param>
    68     80         internal ConnectionEventArgs(
    69     81             SQLiteConnectionEventType eventType,
    70     82             StateChangeEventArgs eventArgs,
    71     83             IDbTransaction transaction,
    72     84             IDbCommand command,
           85  +          IDataReader dataReader,
           86  +          CriticalHandle criticalHandle,
    73     87             string text,
    74     88             object data
    75     89             )
    76     90         {
    77     91             EventType = eventType;
    78     92             EventArgs = eventArgs;
    79     93             Transaction = transaction;
    80     94             Command = command;
           95  +          DataReader = dataReader;
           96  +          CriticalHandle = criticalHandle;
    81     97             Text = text;
    82     98             Data = data;
    83     99         }
    84    100     }
    85    101   
    86    102     /////////////////////////////////////////////////////////////////////////////////////////////////
    87    103   
................................................................................
   487    503           : this(connectionString, false)
   488    504       {
   489    505           // do nothing.
   490    506       }
   491    507   
   492    508       /// <summary>
   493    509       /// Initializes the connection with a pre-existing native connection handle.
          510  +    /// This constructor overload is intended to be used only by the private
          511  +    /// <see cref="SQLiteModule.CreateOrConnect" /> method.
   494    512       /// </summary>
   495    513       /// <param name="db">
   496    514       /// The native connection handle to use.
   497    515       /// </param>
   498    516       /// <param name="fileName">
   499    517       /// The file name corresponding to the native connection handle.
   500    518       /// </param>
................................................................................
   613    631   
   614    632       ///////////////////////////////////////////////////////////////////////////////////////////////
   615    633   
   616    634       /// <summary>
   617    635       /// Raises the <see cref="Changed" /> event.
   618    636       /// </summary>
   619    637       /// <param name="connection">
   620         -    /// The connection associated with this event.
          638  +    /// The connection associated with this event.  If this parameter is not
          639  +    /// null and the specified connection cannot raise events, then the
          640  +    /// registered event handlers will not be invoked.
   621    641       /// </param>
   622    642       /// <param name="e">
   623    643       /// A <see cref="ConnectionEventArgs" /> that contains the event data.
   624    644       /// </param>
   625    645       internal static void OnChanged(
   626    646           SQLiteConnection connection,
   627    647           ConnectionEventArgs e
   628    648           )
   629    649       {
   630         -        if (connection == null)
   631         -            return;
   632         -
   633    650   #if !PLATFORM_COMPACTFRAMEWORK
   634         -        if (!connection.CanRaiseEvents)
          651  +        if ((connection != null) && !connection.CanRaiseEvents)
   635    652               return;
   636    653   #endif
   637    654   
   638    655           SQLiteConnectionEventHandler handlers;
   639    656   
   640    657           lock (_syncRoot)
   641    658           {
................................................................................
   708    725       /// The new managed database connection handle or null if it cannot be
   709    726       /// created.
   710    727       /// </returns>
   711    728       public static object CreateHandle(
   712    729           IntPtr nativeHandle
   713    730           )
   714    731       {
   715         -        if (nativeHandle == IntPtr.Zero) return null;
   716         -        return new SQLiteConnectionHandle(nativeHandle, true);
          732  +        SQLiteConnectionHandle result;
          733  +
          734  +        try
          735  +        {
          736  +            // do nothing.
          737  +        }
          738  +        finally /* NOTE: Thread.Abort() protection. */
          739  +        {
          740  +            result = (nativeHandle != IntPtr.Zero) ?
          741  +                new SQLiteConnectionHandle(nativeHandle, true) : null;
          742  +        }
          743  +
          744  +        if (result != null)
          745  +        {
          746  +            SQLiteConnection.OnChanged(null, new ConnectionEventArgs(
          747  +                SQLiteConnectionEventType.NewCriticalHandle, null, null,
          748  +                null, null, result, null, new object[] { nativeHandle }));
          749  +        }
          750  +
          751  +        return result;
   717    752       }
   718    753   
   719    754       ///////////////////////////////////////////////////////////////////////////////////////////////
   720    755   
   721    756       #region Backup API Members
   722    757       /// <summary>
   723    758       /// Backs up the database, using the specified database connection as the
................................................................................
  1133   1168         if (isolationLevel != IsolationLevel.Serializable && isolationLevel != IsolationLevel.ReadCommitted)
  1134   1169           throw new ArgumentException("isolationLevel");
  1135   1170   
  1136   1171         SQLiteTransaction transaction =
  1137   1172             new SQLiteTransaction(this, isolationLevel != IsolationLevel.Serializable);
  1138   1173   
  1139   1174         OnChanged(this, new ConnectionEventArgs(
  1140         -          SQLiteConnectionEventType.NewTransaction, null, transaction, null, null, null));
         1175  +          SQLiteConnectionEventType.NewTransaction, null, transaction,
         1176  +          null, null, null, null, null));
  1141   1177   
  1142   1178         return transaction;
  1143   1179       }
  1144   1180   
  1145   1181       /// <summary>
  1146   1182       /// This method is not implemented; however, the <see cref="Changed" />
  1147   1183       /// event will still be raised.
................................................................................
  1148   1184       /// </summary>
  1149   1185       /// <param name="databaseName"></param>
  1150   1186       public override void ChangeDatabase(string databaseName)
  1151   1187       {
  1152   1188         CheckDisposed();
  1153   1189   
  1154   1190         OnChanged(this, new ConnectionEventArgs(
  1155         -          SQLiteConnectionEventType.ChangeDatabase, null, null, null, databaseName, null));
         1191  +          SQLiteConnectionEventType.ChangeDatabase, null, null, null, null,
         1192  +          null, databaseName, null));
  1156   1193   
  1157   1194         throw new NotImplementedException(); // NOTE: For legacy compatibility.
  1158   1195       }
  1159   1196   
  1160   1197       /// <summary>
  1161   1198       /// When the database connection is closed, all commands linked to this connection are automatically reset.
  1162   1199       /// </summary>
  1163   1200       public override void Close()
  1164   1201       {
  1165   1202         CheckDisposed();
  1166   1203   
  1167   1204         OnChanged(this, new ConnectionEventArgs(
  1168         -          SQLiteConnectionEventType.Closing, null, null, null, null, null));
         1205  +          SQLiteConnectionEventType.Closing, null, null, null, null, null,
         1206  +          null, null));
  1169   1207   
  1170   1208         if (_sql != null)
  1171   1209         {
  1172   1210   #if !PLATFORM_COMPACTFRAMEWORK
  1173   1211           if (_enlistment != null)
  1174   1212           {
  1175   1213             // If the connection is enlisted in a transaction scope and the scope is still active,
................................................................................
  1197   1235           _transactionLevel = 0;
  1198   1236         }
  1199   1237   
  1200   1238         StateChangeEventArgs eventArgs = null;
  1201   1239         OnStateChange(ConnectionState.Closed, ref eventArgs);
  1202   1240   
  1203   1241         OnChanged(this, new ConnectionEventArgs(
  1204         -          SQLiteConnectionEventType.Closed, eventArgs, null, null, null, null));
         1242  +          SQLiteConnectionEventType.Closed, eventArgs, null, null, null,
         1243  +          null, null, null));
  1205   1244       }
  1206   1245   
  1207   1246       /// <summary>
  1208   1247       /// Returns the number of pool entries for the file name associated with this connection.
  1209   1248       /// </summary>
  1210   1249       public int PoolCount
  1211   1250       {
................................................................................
  1659   1698           throw new ArgumentException("Unable to enlist in transaction, a local transaction already exists");
  1660   1699         else if (transaction == null)
  1661   1700           throw new ArgumentNullException("Unable to enlist in transaction, it is null");
  1662   1701   
  1663   1702         _enlistment = new SQLiteEnlistment(this, transaction);
  1664   1703   
  1665   1704         OnChanged(this, new ConnectionEventArgs(
  1666         -          SQLiteConnectionEventType.EnlistTransaction, null, null, null, null, _enlistment));
         1705  +          SQLiteConnectionEventType.EnlistTransaction, null, null, null, null,
         1706  +          null, null, new object[] { _enlistment }));
  1667   1707       }
  1668   1708   #endif
  1669   1709   
  1670   1710       /// <summary>
  1671   1711       /// Looks for a key in the array of key/values of the parameter string.  If not found, return the specified default value
  1672   1712       /// </summary>
  1673   1713       /// <param name="items">The list to look in</param>
................................................................................
  1948   1988       /// Opens the connection using the parameters found in the <see cref="ConnectionString" />.
  1949   1989       /// </summary>
  1950   1990       public override void Open()
  1951   1991       {
  1952   1992         CheckDisposed();
  1953   1993   
  1954   1994         OnChanged(this, new ConnectionEventArgs(
  1955         -          SQLiteConnectionEventType.Opening, null, null, null, null, null));
         1995  +          SQLiteConnectionEventType.Opening, null, null, null, null, null,
         1996  +          null, null));
  1956   1997   
  1957   1998         if (_connectionState != ConnectionState.Closed)
  1958   1999           throw new InvalidOperationException();
  1959   2000   
  1960   2001         Close();
  1961   2002   
  1962   2003         SortedList<string, string> opts = ParseConnectionString(
  1963   2004             _connectionString, _parseViaFramework);
  1964   2005   
  1965   2006         OnChanged(this, new ConnectionEventArgs(
  1966         -          SQLiteConnectionEventType.ConnectionString, null, null, null, _connectionString, opts));
         2007  +          SQLiteConnectionEventType.ConnectionString, null, null, null, null,
         2008  +          null, _connectionString, new object[] { opts }));
  1967   2009   
  1968   2010         object enumValue;
  1969   2011   
  1970   2012         enumValue = TryParseEnum(typeof(SQLiteConnectionFlags), FindKey(opts, "Flags", DefaultFlags.ToString()), true);
  1971   2013         _flags = (enumValue is SQLiteConnectionFlags) ? (SQLiteConnectionFlags)enumValue : DefaultFlags;
  1972   2014   
  1973   2015         bool fullUri = false;
................................................................................
  2189   2231   
  2190   2232             _connectionState = oldstate;
  2191   2233   
  2192   2234             StateChangeEventArgs eventArgs = null;
  2193   2235             OnStateChange(ConnectionState.Open, ref eventArgs);
  2194   2236   
  2195   2237             OnChanged(this, new ConnectionEventArgs(
  2196         -              SQLiteConnectionEventType.Opened, eventArgs, null, null, null, null));
         2238  +              SQLiteConnectionEventType.Opened, eventArgs, null, null, null,
         2239  +              null, null, null));
  2197   2240           }
  2198   2241           catch
  2199   2242           {
  2200   2243             _connectionState = oldstate;
  2201   2244             throw;
  2202   2245           }
  2203   2246         }

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

  1299   1299         NewCommand = 7,
  1300   1300   
  1301   1301         /// <summary>
  1302   1302         /// A data reader was created using the connection.
  1303   1303         /// </summary>
  1304   1304         NewDataReader = 8,
  1305   1305   
         1306  +      /// <summary>
         1307  +      /// An instance of a <see cref="CriticalHandle" /> derived class has
         1308  +      /// been created to wrap a native resource.
         1309  +      /// </summary>
         1310  +      NewCriticalHandle = 9,
         1311  +
  1306   1312         /// <summary>
  1307   1313         /// The connection is being closed.
  1308   1314         /// </summary>
  1309         -      Closing = 9,
         1315  +      Closing = 10,
  1310   1316   
  1311   1317         /// <summary>
  1312   1318         /// The connection was closed.
  1313   1319         /// </summary>
  1314         -      Closed = 10
         1320  +      Closed = 11
  1315   1321     }
  1316   1322   
  1317   1323     /// <summary>
  1318         -  /// This implementation of SQLite for ADO.NET can process date/time fields in databases in only one of three formats.  Ticks, ISO8601
  1319         -  /// and JulianDay.
         1324  +  /// This implementation of SQLite for ADO.NET can process date/time fields in
         1325  +  /// databases in one of six formats.
  1320   1326     /// </summary>
  1321   1327     /// <remarks>
  1322         -  /// ISO8601 is more compatible, readable, fully-processable, but less accurate as it doesn't provide time down to fractions of a second.
  1323         -  /// JulianDay is the numeric format the SQLite uses internally and is arguably the most compatible with 3rd party tools.  It is
  1324         -  /// not readable as text without post-processing.
  1325         -  /// Ticks less compatible with 3rd party tools that query the database, and renders the DateTime field unreadable as text without post-processing.
         1328  +  /// ISO8601 format is more compatible, readable, fully-processable, but less
         1329  +  /// accurate as it does not provide time down to fractions of a second.
         1330  +  /// JulianDay is the numeric format the SQLite uses internally and is arguably
         1331  +  /// the most compatible with 3rd party tools.  It is not readable as text
         1332  +  /// without post-processing.  Ticks less compatible with 3rd party tools that
         1333  +  /// query the database, and renders the DateTime field unreadable as text
         1334  +  /// without post-processing.  UnixEpoch is more compatible with Unix systems.
         1335  +  /// InvariantCulture allows the configured format for the invariant culture
         1336  +  /// format to be used and is human readable.  CurrentCulture allows the
         1337  +  /// configured format for the current culture to be used and is also human
         1338  +  /// readable.
  1326   1339     ///
  1327         -  /// The preferred order of choosing a datetime format is JulianDay, ISO8601, and then Ticks.  Ticks is mainly present for legacy
  1328         -  /// code support.
         1340  +  /// The preferred order of choosing a DateTime format is JulianDay, ISO8601,
         1341  +  /// and then Ticks.  Ticks is mainly present for legacy code support.
  1329   1342     /// </remarks>
  1330   1343     public enum SQLiteDateFormats
  1331   1344     {
  1332   1345       /// <summary>
  1333   1346       /// Use the value of DateTime.Ticks.  This value is not recommended and is not well supported with LINQ.
  1334   1347       /// </summary>
  1335   1348       Ticks = 0,

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

   104    104         _activeStatementIndex = -1;
   105    105         _rowsAffected = -1;
   106    106   
   107    107         if (_command != null)
   108    108         {
   109    109             SQLiteConnection.OnChanged(_command.Connection,
   110    110                 new ConnectionEventArgs(SQLiteConnectionEventType.NewDataReader,
   111         -                  null, null, _command, null, new object[] { this, behave }));
          111  +              null, null, _command, this, null, null, new object[] { behave }));
   112    112   
   113    113             NextResult();
   114    114         }
   115    115       }
   116    116   
   117    117       ///////////////////////////////////////////////////////////////////////////////////////////////
   118    118