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

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

Overview
Comment:Obtain a lock on the connection handle prior to finalizing a statement and/or finishing a backup object.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: fbf498a216efbfd73c2ab8236455c06b0e94a634
User & Date: mistachkin 2012-05-03 17:15:41
Context
2012-05-03
17:46
Update test case for ticket [996d13cd87] to run with and without connection pooling enabled. check-in: ead1f27df0 user: mistachkin tags: trunk
17:15
Obtain a lock on the connection handle prior to finalizing a statement and/or finishing a backup object. check-in: fbf498a216 user: mistachkin tags: trunk
16:44
Expand scope for the GC.KeepAlive call in the SQLiteConnectionPool.Add method. check-in: d13b6a5885 user: mistachkin tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

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

   534    534             }
   535    535           }
   536    536   
   537    537           if (n > 0) throw new SQLiteException(n, GetLastError());
   538    538   
   539    539           strRemain = UTF8ToString(ptr, len);
   540    540   
   541         -        if (stmt != IntPtr.Zero) cmd = new SQLiteStatement(this, flags, new SQLiteStatementHandle(stmt), strSql.Substring(0, strSql.Length - strRemain.Length), previous);
          541  +        if (stmt != IntPtr.Zero) cmd = new SQLiteStatement(this, flags, new SQLiteStatementHandle(_sql, stmt), strSql.Substring(0, strSql.Length - strRemain.Length), previous);
   542    542   
   543    543           return cmd;
   544    544         }
   545    545         finally
   546    546         {
   547    547           handle.Free();
   548    548         }
................................................................................
  1476   1476           IntPtr backup = UnsafeNativeMethods.sqlite3_backup_init(
  1477   1477               destHandle, zDestName, sourceHandle, zSourceName);
  1478   1478   
  1479   1479           if (backup == IntPtr.Zero)
  1480   1480               throw new SQLiteException(ResultCode(), GetLastError());
  1481   1481   
  1482   1482           return new SQLiteBackup(
  1483         -            this, new SQLiteBackupHandle(backup), destHandle, zDestName,
  1484         -            sourceHandle, zSourceName);
         1483  +            this, new SQLiteBackupHandle(destHandle, backup),
         1484  +            destHandle, zDestName, sourceHandle, zSourceName);
  1485   1485       }
  1486   1486   
  1487   1487       /// <summary>
  1488   1488       /// Copies up to N pages from the source database to the destination
  1489   1489       /// database associated with the specified backup object.
  1490   1490       /// </summary>
  1491   1491       /// <param name="backup">The backup object to use.</param>

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

   363    363           }
   364    364   
   365    365   #pragma warning disable 162
   366    366           GC.KeepAlive(hdl); /* NOTE: Unreachable code. */
   367    367   #pragma warning restore 162
   368    368       }
   369    369   
   370         -    internal static void FinishBackup(IntPtr backup)
          370  +    internal static void FinishBackup(SQLiteConnectionHandle hdl, IntPtr backup)
   371    371       {
   372         -        if (backup == IntPtr.Zero) return;
   373         -        int n = UnsafeNativeMethods.sqlite3_backup_finish(backup);
   374         -        if (n > 0) throw new SQLiteException(n, null);
          372  +        if ((hdl == null) || (backup == IntPtr.Zero)) return;
          373  +        lock (hdl)
          374  +        {
          375  +            int n = UnsafeNativeMethods.sqlite3_backup_finish(backup);
          376  +            if (n > 0) throw new SQLiteException(n, null);
          377  +        }
   375    378       }
   376    379   
   377         -    internal static void FinalizeStatement(IntPtr stmt)
          380  +    internal static void FinalizeStatement(SQLiteConnectionHandle hdl, IntPtr stmt)
   378    381       {
   379         -        if (stmt == IntPtr.Zero) return;
          382  +        if ((hdl == null) || (stmt == IntPtr.Zero)) return;
          383  +        lock (hdl)
          384  +        {
   380    385   #if !SQLITE_STANDARD
   381         -        int n = UnsafeNativeMethods.sqlite3_finalize_interop(stmt);
          386  +            int n = UnsafeNativeMethods.sqlite3_finalize_interop(stmt);
   382    387   #else
   383         -        int n = UnsafeNativeMethods.sqlite3_finalize(stmt);
          388  +            int n = UnsafeNativeMethods.sqlite3_finalize(stmt);
   384    389   #endif
   385         -        if (n > 0) throw new SQLiteException(n, null);
          390  +            if (n > 0) throw new SQLiteException(n, null);
          391  +        }
   386    392       }
   387    393   
   388    394       internal static void CloseConnection(SQLiteConnectionHandle hdl, IntPtr db)
   389    395       {
   390    396           if ((hdl == null) || (db == IntPtr.Zero)) return;
   391    397           lock (hdl)
   392    398           {

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

  1453   1453       }
  1454   1454   #endif
  1455   1455     }
  1456   1456   
  1457   1457     // Provides finalization support for unmanaged SQLite statements.
  1458   1458     internal class SQLiteStatementHandle : CriticalHandle
  1459   1459     {
         1460  +    private SQLiteConnectionHandle cnn;
         1461  +
  1460   1462       public static implicit operator IntPtr(SQLiteStatementHandle stmt)
  1461   1463       {
  1462   1464         return (stmt != null) ? stmt.handle : IntPtr.Zero;
  1463   1465       }
  1464   1466   
  1465         -    internal SQLiteStatementHandle(IntPtr stmt)
         1467  +    internal SQLiteStatementHandle(SQLiteConnectionHandle cnn, IntPtr stmt)
  1466   1468         : this()
  1467   1469       {
         1470  +      this.cnn = cnn;
  1468   1471         SetHandle(stmt);
  1469   1472       }
  1470   1473   
  1471   1474       private SQLiteStatementHandle()
  1472   1475         : base(IntPtr.Zero)
  1473   1476       {
  1474   1477       }
................................................................................
  1478   1481         try
  1479   1482         {
  1480   1483   #if !PLATFORM_COMPACTFRAMEWORK
  1481   1484           IntPtr localHandle = Interlocked.Exchange(
  1482   1485             ref handle, IntPtr.Zero);
  1483   1486   
  1484   1487           if (localHandle != IntPtr.Zero)
  1485         -          SQLiteBase.FinalizeStatement(localHandle);
         1488  +          SQLiteBase.FinalizeStatement(cnn, localHandle);
  1486   1489   
  1487   1490   #if DEBUG && !NET_COMPACT_20
  1488   1491           try
  1489   1492           {
  1490   1493             Trace.WriteLine(String.Format(
  1491   1494                 "FinalizeStatement: {0}", localHandle));
  1492   1495           }
................................................................................
  1493   1496           catch
  1494   1497           {
  1495   1498           }
  1496   1499   #endif
  1497   1500   #else
  1498   1501           if (handle != IntPtr.Zero)
  1499   1502           {
  1500         -          SQLiteBase.FinalizeStatement(handle);
         1503  +          SQLiteBase.FinalizeStatement(cnn, handle);
  1501   1504             SetHandle(IntPtr.Zero);
  1502   1505           }
  1503   1506   #endif
  1504   1507   
  1505   1508   #if DEBUG
  1506   1509           return true;
  1507   1510   #endif
................................................................................
  1547   1550       }
  1548   1551   #endif
  1549   1552     }
  1550   1553   
  1551   1554     // Provides finalization support for unmanaged SQLite backup objects.
  1552   1555     internal class SQLiteBackupHandle : CriticalHandle
  1553   1556     {
         1557  +      private SQLiteConnectionHandle cnn;
         1558  +
  1554   1559         public static implicit operator IntPtr(SQLiteBackupHandle backup)
  1555   1560         {
  1556   1561             return (backup != null) ? backup.handle : IntPtr.Zero;
  1557   1562         }
  1558   1563   
  1559         -      internal SQLiteBackupHandle(IntPtr backup)
         1564  +      internal SQLiteBackupHandle(SQLiteConnectionHandle cnn, IntPtr backup)
  1560   1565             : this()
  1561   1566         {
         1567  +          this.cnn = cnn;
  1562   1568             SetHandle(backup);
  1563   1569         }
  1564   1570   
  1565   1571         private SQLiteBackupHandle()
  1566   1572             : base(IntPtr.Zero)
  1567   1573         {
  1568   1574         }
................................................................................
  1572   1578             try
  1573   1579             {
  1574   1580   #if !PLATFORM_COMPACTFRAMEWORK
  1575   1581                 IntPtr localHandle = Interlocked.Exchange(
  1576   1582                     ref handle, IntPtr.Zero);
  1577   1583   
  1578   1584                 if (localHandle != IntPtr.Zero)
  1579         -                  SQLiteBase.FinishBackup(localHandle);
         1585  +                  SQLiteBase.FinishBackup(cnn, localHandle);
  1580   1586   
  1581   1587   #if DEBUG && !NET_COMPACT_20
  1582   1588                 try
  1583   1589                 {
  1584   1590                     Trace.WriteLine(String.Format(
  1585   1591                         "FinishBackup: {0}", localHandle));
  1586   1592                 }
................................................................................
  1587   1593                 catch
  1588   1594                 {
  1589   1595                 }
  1590   1596   #endif
  1591   1597   #else
  1592   1598                 if (handle != IntPtr.Zero)
  1593   1599                 {
  1594         -                SQLiteBase.FinishBackup(handle);
         1600  +                SQLiteBase.FinishBackup(cnn, handle);
  1595   1601                   SetHandle(IntPtr.Zero);
  1596   1602                 }
  1597   1603   #endif
  1598   1604   
  1599   1605   #if DEBUG
  1600   1606                 return true;
  1601   1607   #endif