[mono.data.sqlite] Using sqlite_close_v2 when available
authorMiguel de Icaza <miguel@gnome.org>
Wed, 23 Sep 2015 19:34:00 +0000 (15:34 -0400)
committerMiguel de Icaza <miguel@gnome.org>
Wed, 23 Sep 2015 19:34:00 +0000 (15:34 -0400)
From Matthew Leibowitz (mattleibo)

This is the recommended function for garbage collected languages.
http://sqlite.org/c3ref/close.html

The sqlite3_close_v2() interface is intended for use with host
languages that are garbage collected, and where the order in which
destructors are called is arbitrary.

Falls back to old sqlite3_close if we are on an old system

Useful for ADO.NET where the connection os often closed, but the
commands are re-usable

Mostly visible on Windows operating systems

This snippet should fail with a System.IO.IOException using the
current build of Mono on Windows:

    string filename = "test_" + Guid.NewGuid ().ToString ("N") + ".db";
    SqliteConnection conn = new SqliteConnection ("Data Source=" + filename);
    conn.Open ();
    SqliteCommand cmd = conn.CreateCommand ();
    cmd.CommandText = "PRAGMA legacy_file_format;";
    cmd.ExecuteScalar ();
    // close connection before the command
    conn.Dispose ();
    // then close the command
    cmd.Dispose ();
    // the locks should be released, and we should be able to delete the database
    File.Delete (filename);

mcs/class/Mono.Data.Sqlite/Mono.Data.Sqlite_2.0/SQLiteBase.cs
mcs/class/Mono.Data.Sqlite/Mono.Data.Sqlite_2.0/UnsafeNativeMethods.cs
mcs/class/Mono.Data.Sqlite/Test/SqliteConnectionTest.cs

index e698dde9d6d208f21c70257a30d4a0e639624cbf..df8a5d787ab0daefe2ea5714dc621b1342f9f8b2 100644 (file)
@@ -206,8 +206,13 @@ namespace Mono.Data.Sqlite
 #if !SQLITE_STANDARD\r
         int n = UnsafeNativeMethods.sqlite3_close_interop(db);\r
 #else\r
-      ResetConnection(db);\r
-      int n = UnsafeNativeMethods.sqlite3_close(db);\r
+        ResetConnection(db);\r
+        int n;\r
+        try {\r
+          n = UnsafeNativeMethods.sqlite3_close_v2(db);\r
+        } catch (EntryPointNotFoundException) {\r
+          n = UnsafeNativeMethods.sqlite3_close(db);\r
+        }\r
 #endif\r
         if (n > 0) throw new SqliteException(n, SQLiteLastError(db));\r
       }\r
index c5ae7c6ff2cf89e15ebc564530921fa6c3d0474b..4b440b951ed56cd07ede1b2c0f6aa3a3ebc21615 100644 (file)
@@ -135,6 +135,13 @@ namespace Mono.Data.Sqlite
     [DllImport(SQLITE_DLL)]\r
 #endif\r
     internal static extern int sqlite3_close(IntPtr db);\r
+               \r
+#if !PLATFORM_COMPACTFRAMEWORK\r
+    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]\r
+#else\r
+    [DllImport(SQLITE_DLL)]\r
+#endif\r
+    internal static extern int sqlite3_close_v2(IntPtr db);\r
 \r
 #if !PLATFORM_COMPACTFRAMEWORK\r
     [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]\r
index d65ee3f9ae6179fd80d5d8b06ff97d596b5f5b55..9afb83a2b39676721deb8f0bb40537f0ed88b67f 100644 (file)
@@ -44,6 +44,26 @@ namespace MonoTests.Mono.Data.Sqlite
                 readonly static string _connectionString = "URI=file://" + _uri + ", version=3";
                 SqliteConnection _conn = new SqliteConnection ();
 
+               [Test]
+               public void ReleaseDatabaseFileHandles ()
+               {
+                       _conn.ConnectionString = _connectionString;
+                       _conn.Open ();
+                       
+                       SqliteCommand cmd = _conn.CreateCommand ();
+                       cmd.CommandText = "PRAGMA legacy_file_format;";
+                       cmd.ExecuteScalar ();
+                       
+                       // close connection before the command
+                       _conn.Dispose ();
+                       
+                       // then close the command
+                       cmd.Dispose ();
+                       
+                       // the locks should be released, and we should be able to delete the database
+                       File.Delete (_uri);
+               }
+
                 [Test]
                 [ExpectedException (typeof (ArgumentNullException))]
                 public void ConnectionStringTest_Null ()