diff --git a/Microsoft.Research/Clousot.Cache/Clousot.Cache.csproj b/Microsoft.Research/Clousot.Cache/Clousot.Cache.csproj
index 06ff85a4..0f24a8bb 100644
--- a/Microsoft.Research/Clousot.Cache/Clousot.Cache.csproj
+++ b/Microsoft.Research/Clousot.Cache/Clousot.Cache.csproj
@@ -116,6 +116,7 @@
+
diff --git a/Microsoft.Research/Clousot.Cache/SQLCacheModel.cs b/Microsoft.Research/Clousot.Cache/SQLCacheModel.cs
index 0e37ac77..af5ffe9e 100644
--- a/Microsoft.Research/Clousot.Cache/SQLCacheModel.cs
+++ b/Microsoft.Research/Clousot.Cache/SQLCacheModel.cs
@@ -16,6 +16,9 @@
using System;
using System.Collections.Generic;
+using System.Data.Common;
+using System.Data.Linq;
+using System.Globalization;
using System.Linq;
using System.Text;
using Microsoft.Research.CodeAnalysis.Caching.Models;
@@ -558,6 +561,45 @@ public string CacheName
{
get { return this.cachename; }
}
+
+ protected void DetachDeletedDb(string connection)
+ {
+ // If anyone has manually deleted the cache file, it might be still registered with LocalDB.
+ // If this is the case, we can't create a new database and the user is stuck unless he knows the tricky internals of LocalDB and how to get rid of the registration.
+ // => If we use LocalDB and the file does not exist, we try to detach it.
+ try
+ {
+ var connectionString = new DbConnectionStringBuilder { ConnectionString = connection };
+ var fileName = (string)connectionString["AttachDbFileName"];
+ if (File.Exists(fileName))
+ return;
+
+ var catalog = (string)connectionString["Initial Catalog"];
+ var dataSource = (string)connectionString["Data Source"];
+
+ using (var master = new DataContext(string.Format(CultureInfo.InvariantCulture, @"Data Source={0};Initial Catalog=master;Integrated Security=True", dataSource)))
+ {
+ master.ExecuteCommand(@"exec sp_detach_db {0}", catalog);
+ }
+ }
+ catch (ArgumentException)
+ {
+ // Not using LocalDB at all (any of the connection string parameters did not exist).
+ }
+ catch (SqlException)
+ {
+ // The file was never registered (first time used) or is already detached.
+ }
+ catch (Exception ex)
+ {
+ // Ignore other errors, could be any DbProvider specific exception.
+ // Usually we won't get here, but the active provider might not be LocalDB, in this case we know nothing about the provider and the exceptions it might raise.
+ if (this.trace)
+ {
+ Console.WriteLine("[cache] DetachDeletedDb failed: {0}", ex.Message);
+ }
+ }
+ }
}
public class SqlCacheModelNoCreate : SQLCacheModel
@@ -614,6 +656,8 @@ public SqlCacheModelClearExisting(string connection, string cachename, bool trac
: base(connection, cachename, trace)
{
Contract.Requires(cachename != null);
+
+ DetachDeletedDb(connection);
}
}
@@ -637,6 +681,8 @@ public SqlCacheModelDropOnModelChange(string connection, string cachename, bool
: base(connection, cachename, trace)
{
Contract.Requires(cachename != null);
+
+ DetachDeletedDb(connection);
}
}