System.Data.SQLite
Check-in [0ed439a5e7]
Not logged in

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

Overview
Comment:Fix potential race condition between SQLiteBase.CloseConnection (via GC) and SQLiteBase.ResetConnection (via pool) when used on the same connection handle object.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | tkt-996d13cd87
Files: files | file ages | folders
SHA1: 0ed439a5e7c51b6f95bc3e1461ad1f03a4e45304
User & Date: mistachkin 2012-04-30 17:17:26
Context
2012-04-30
17:18
Remove superfluous using statement. check-in: b8fb8d4b6a user: mistachkin tags: tkt-996d13cd87
17:17
Fix potential race condition between SQLiteBase.CloseConnection (via GC) and SQLiteBase.ResetConnection (via pool) when used on the same connection handle object. check-in: 0ed439a5e7 user: mistachkin tags: tkt-996d13cd87
16:27
Remove superfluous lock from the static helper methods in the SQLiteBase class. check-in: c593d21c60 user: mistachkin tags: tkt-996d13cd87
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

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

113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
    // resources belonging to the previously-registered functions.
    internal override void Close()
    {
      if (_sql != null)
      {
          if (_usePool)
          {
              SQLiteBase.ResetConnection(_sql);
              SQLiteConnectionPool.Add(_fileName, _sql, _poolVersion);

#if DEBUG && !NET_COMPACT_20
              Trace.WriteLine(String.Format("Close (Pool): {0}", _sql));
#endif
          }
          else







|







113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
    // resources belonging to the previously-registered functions.
    internal override void Close()
    {
      if (_sql != null)
      {
          if (_usePool)
          {
              SQLiteBase.ResetConnection(_sql, _sql);
              SQLiteConnectionPool.Add(_fileName, _sql, _poolVersion);

#if DEBUG && !NET_COMPACT_20
              Trace.WriteLine(String.Format("Close (Pool): {0}", _sql));
#endif
          }
          else

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

4
5
6
7
8
9
10

11
12
13
14
15
16
17
...
369
370
371
372
373
374
375
376
377
378


379
380
381
382
383
384
385
386
387

388
389
390


391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409

410
411
412
413
414
415
416
 * 
 * Released to the public domain, use at your own risk!
 ********************************************************/

namespace System.Data.SQLite
{
  using System;


  /// <summary>
  /// This internal class provides the foundation of SQLite support.  It defines all the abstract members needed to implement
  /// a SQLite data provider, and inherits from SQLiteConvert which allows for simple translations of string to and from SQLite.
  /// </summary>
  internal abstract class SQLiteBase : SQLiteConvert, IDisposable
  {
................................................................................
        int n = UnsafeNativeMethods.sqlite3_finalize_interop(stmt);
#else
        int n = UnsafeNativeMethods.sqlite3_finalize(stmt);
#endif
        if (n > 0) throw new SQLiteException(n, null);
    }

    internal static void CloseConnection(IntPtr db)
    {
        if (db == IntPtr.Zero) return;


#if !SQLITE_STANDARD
        int n = UnsafeNativeMethods.sqlite3_close_interop(db);
#else
        ResetConnection(db);
        int n = UnsafeNativeMethods.sqlite3_close(db);
#endif
        if (n > 0) throw new SQLiteException(n, SQLiteLastError(db));
    }


    internal static void ResetConnection(IntPtr db)
    {
        if (db == IntPtr.Zero) return;


        IntPtr stmt = IntPtr.Zero;
        int n;
        do
        {
            stmt = UnsafeNativeMethods.sqlite3_next_stmt(db, stmt);
            if (stmt != IntPtr.Zero)
            {
#if !SQLITE_STANDARD
                n = UnsafeNativeMethods.sqlite3_reset_interop(stmt);
#else
                n = UnsafeNativeMethods.sqlite3_reset(stmt);
#endif
            }
        } while (stmt != IntPtr.Zero);

        if (IsAutocommit(db) == false) // a transaction is pending on the connection
        {
            n = UnsafeNativeMethods.sqlite3_exec(db, ToUTF8("ROLLBACK"), IntPtr.Zero, IntPtr.Zero, out stmt);
            if (n > 0) throw new SQLiteException(n, SQLiteLastError(db));

        }
    }

    internal static bool IsAutocommit(IntPtr db)
    {
      if (db == IntPtr.Zero) return false;
      return (UnsafeNativeMethods.sqlite3_get_autocommit(db) == 1);







>







 







|

|
>
>

|

|
|

|
|
|
>
|

|
>
>
|
|
|
|
|
|
|

|



|
|

|
|
|
|
>







4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
...
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
 * 
 * Released to the public domain, use at your own risk!
 ********************************************************/

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

  /// <summary>
  /// This internal class provides the foundation of SQLite support.  It defines all the abstract members needed to implement
  /// a SQLite data provider, and inherits from SQLiteConvert which allows for simple translations of string to and from SQLite.
  /// </summary>
  internal abstract class SQLiteBase : SQLiteConvert, IDisposable
  {
................................................................................
        int n = UnsafeNativeMethods.sqlite3_finalize_interop(stmt);
#else
        int n = UnsafeNativeMethods.sqlite3_finalize(stmt);
#endif
        if (n > 0) throw new SQLiteException(n, null);
    }

    internal static void CloseConnection(SQLiteConnectionHandle hdl, IntPtr db)
    {
        if ((hdl == null) || (db == IntPtr.Zero)) return;
        lock (hdl)
        {
#if !SQLITE_STANDARD
            int n = UnsafeNativeMethods.sqlite3_close_interop(db);
#else
            ResetConnection(hdl, db);
            int n = UnsafeNativeMethods.sqlite3_close(db);
#endif
            if (n > 0) throw new SQLiteException(n, SQLiteLastError(db));
        }
    }

    internal static void ResetConnection(SQLiteConnectionHandle hdl, IntPtr db)
    {
        if ((hdl == null) || (db == IntPtr.Zero)) return;
        lock (hdl)
        {
            IntPtr stmt = IntPtr.Zero;
            int n;
            do
            {
                stmt = UnsafeNativeMethods.sqlite3_next_stmt(db, stmt);
                if (stmt != IntPtr.Zero)
                {
#if !SQLITE_STANDARD
                    n = UnsafeNativeMethods.sqlite3_reset_interop(stmt);
#else
                n = UnsafeNativeMethods.sqlite3_reset(stmt);
#endif
                }
            } while (stmt != IntPtr.Zero);

            if (IsAutocommit(db) == false) // a transaction is pending on the connection
            {
                n = UnsafeNativeMethods.sqlite3_exec(db, ToUTF8("ROLLBACK"), IntPtr.Zero, IntPtr.Zero, out stmt);
                if (n > 0) throw new SQLiteException(n, SQLiteLastError(db));
            }
        }
    }

    internal static bool IsAutocommit(IntPtr db)
    {
      if (db == IntPtr.Zero) return false;
      return (UnsafeNativeMethods.sqlite3_get_autocommit(db) == 1);

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

1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
....
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
      try
      {
#if !PLATFORM_COMPACTFRAMEWORK
        IntPtr localHandle = Interlocked.Exchange(
          ref handle, IntPtr.Zero);

        if (localHandle != IntPtr.Zero)
          SQLiteBase.CloseConnection(localHandle);

#if DEBUG && !NET_COMPACT_20
        try
        {
          Trace.WriteLine(String.Format(
              "CloseConnection: {0}", localHandle));
        }
................................................................................
        catch
        {
        }
#endif
#else
        if (handle != IntPtr.Zero)
        {
          SQLiteBase.CloseConnection(handle);
          SetHandle(IntPtr.Zero);
        }
#endif

#if DEBUG
        return true;
#endif







|







 







|







1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
....
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
      try
      {
#if !PLATFORM_COMPACTFRAMEWORK
        IntPtr localHandle = Interlocked.Exchange(
          ref handle, IntPtr.Zero);

        if (localHandle != IntPtr.Zero)
          SQLiteBase.CloseConnection(this, localHandle);

#if DEBUG && !NET_COMPACT_20
        try
        {
          Trace.WriteLine(String.Format(
              "CloseConnection: {0}", localHandle));
        }
................................................................................
        catch
        {
        }
#endif
#else
        if (handle != IntPtr.Zero)
        {
          SQLiteBase.CloseConnection(this, handle);
          SetHandle(IntPtr.Zero);
        }
#endif

#if DEBUG
        return true;
#endif