restore sqlite indexes on alter.
This commit is contained in:
parent
4196b7eedb
commit
2068b732a2
|
@ -1,4 +1,5 @@
|
|||
using FizzWare.NBuilder;
|
||||
using System.Collections.Generic;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
@ -18,8 +19,6 @@ namespace NzbDrone.Core.Test.Datastore
|
|||
_subject = Mocker.Resolve<SQLiteMigrationHelper>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_parse_existing_columns()
|
||||
{
|
||||
|
@ -37,7 +36,7 @@ namespace NzbDrone.Core.Test.Datastore
|
|||
var columns = _subject.GetColumns("Series");
|
||||
columns.Remove("Title");
|
||||
|
||||
_subject.CreateTable("Series_New", columns.Values);
|
||||
_subject.CreateTable("Series_New", columns.Values, new List<SQLiteMigrationHelper.SQLiteIndex>());
|
||||
|
||||
var newColumns = _subject.GetColumns("Series_New");
|
||||
|
||||
|
@ -45,12 +44,6 @@ namespace NzbDrone.Core.Test.Datastore
|
|||
newColumns.Should().NotContainKey("Title");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_get_zero_count_on_empty_table()
|
||||
{
|
||||
_subject.GetRowCount("Series").Should().Be(0);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_transfer_empty_tables()
|
||||
|
@ -58,7 +51,7 @@ namespace NzbDrone.Core.Test.Datastore
|
|||
var columns = _subject.GetColumns("Series");
|
||||
columns.Remove("Title");
|
||||
|
||||
_subject.CreateTable("Series_New", columns.Values);
|
||||
_subject.CreateTable("Series_New", columns.Values, new List<SQLiteMigrationHelper.SQLiteIndex>());
|
||||
|
||||
|
||||
_subject.CopyData("Series", "Series_New", columns.Values);
|
||||
|
@ -74,11 +67,40 @@ namespace NzbDrone.Core.Test.Datastore
|
|||
var columns = _subject.GetColumns("Episodes");
|
||||
columns.Remove("Title");
|
||||
|
||||
_subject.CreateTable("Episodes_New", columns.Values);
|
||||
_subject.CreateTable("Episodes_New", columns.Values, new List<SQLiteMigrationHelper.SQLiteIndex>());
|
||||
|
||||
_subject.CopyData("Episodes", "Episodes_New", columns.Values);
|
||||
|
||||
_subject.GetRowCount("Episodes_New").Should().Be(originalEpisodes.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_read_existing_indexes()
|
||||
{
|
||||
var indexes = _subject.GetIndexes("QualitySizes");
|
||||
|
||||
indexes.Should().NotBeEmpty();
|
||||
|
||||
indexes.Should().OnlyContain(c => c != null);
|
||||
indexes.Should().OnlyContain(c => !string.IsNullOrWhiteSpace(c.Column));
|
||||
indexes.Should().OnlyContain(c => c.Table == "QualitySizes");
|
||||
indexes.Should().OnlyContain(c => c.Unique);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_add_indexes_when_creating_new_table()
|
||||
{
|
||||
var columns = _subject.GetColumns("QualitySizes");
|
||||
var indexes = _subject.GetIndexes("QualitySizes");
|
||||
|
||||
|
||||
_subject.CreateTable("QualityB", columns.Values, indexes);
|
||||
|
||||
|
||||
var newIndexes = _subject.GetIndexes("QualityB");
|
||||
|
||||
newIndexes.Should().HaveSameCount(indexes);
|
||||
newIndexes.Should().BeEquivalentTo(columns);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,12 +10,12 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
|
|||
public interface ISQLiteMigrationHelper
|
||||
{
|
||||
Dictionary<String, SQLiteMigrationHelper.SQLiteColumn> GetColumns(string tableName);
|
||||
void CreateTable(string tableName, IEnumerable<SQLiteMigrationHelper.SQLiteColumn> values);
|
||||
void CreateTable(string tableName, IEnumerable<SQLiteMigrationHelper.SQLiteColumn> values, IEnumerable<SQLiteMigrationHelper.SQLiteIndex> indexes);
|
||||
void CopyData(string sourceTable, string destinationTable, IEnumerable<SQLiteMigrationHelper.SQLiteColumn> columns);
|
||||
int GetRowCount(string tableName);
|
||||
void DropTable(string tableName);
|
||||
void RenameTable(string tableName, string newName);
|
||||
SQLiteTransaction BeginTransaction();
|
||||
List<SQLiteMigrationHelper.SQLiteIndex> GetIndexes(string tableName);
|
||||
}
|
||||
|
||||
public class SQLiteMigrationHelper : ISQLiteMigrationHelper
|
||||
|
@ -25,6 +25,9 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
|
|||
private static readonly Regex SchemaRegex = new Regex(@"['\""\[](?<name>\w+)['\""\]]\s(?<schema>[\w-\s]+)",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||||
|
||||
private static readonly Regex IndexRegex = new Regex(@"\(""(?<col>.*)""\s(?<direction>ASC|DESC)\)$",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||||
|
||||
public SQLiteMigrationHelper(IConnectionStringFactory connectionStringFactory, Logger logger)
|
||||
{
|
||||
try
|
||||
|
@ -34,7 +37,7 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.ErrorException("Couldn't open databse " + connectionStringFactory.MainDbConnectionString, e);
|
||||
logger.ErrorException("Couldn't open database " + connectionStringFactory.MainDbConnectionString, e);
|
||||
throw;
|
||||
}
|
||||
|
||||
|
@ -47,6 +50,7 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
|
|||
tableName));
|
||||
|
||||
command.Connection = _connection;
|
||||
|
||||
return (string)command.ExecuteScalar();
|
||||
}
|
||||
|
||||
|
@ -65,14 +69,48 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
|
|||
});
|
||||
}
|
||||
|
||||
public void CreateTable(string tableName, IEnumerable<SQLiteColumn> values)
|
||||
public List<SQLiteIndex> GetIndexes(string tableName)
|
||||
{
|
||||
var command = new SQLiteCommand(string.Format("SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name ='{0}'", tableName));
|
||||
command.Connection = _connection;
|
||||
|
||||
var reader = command.ExecuteReader();
|
||||
var sqls = new List<string>();
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
sqls.Add(reader[0].ToString());
|
||||
}
|
||||
|
||||
|
||||
var indexes = new List<SQLiteIndex>();
|
||||
|
||||
foreach (var indexSql in sqls)
|
||||
{
|
||||
var newIndex = new SQLiteIndex();
|
||||
var matches = IndexRegex.Match(indexSql);
|
||||
|
||||
newIndex.Column = matches.Groups["col"].Value;
|
||||
newIndex.Unique = indexSql.Contains("UNIQUE");
|
||||
newIndex.Table = tableName;
|
||||
|
||||
indexes.Add(newIndex);
|
||||
}
|
||||
|
||||
return indexes;
|
||||
}
|
||||
|
||||
public void CreateTable(string tableName, IEnumerable<SQLiteColumn> values, IEnumerable<SQLiteIndex> indexes)
|
||||
{
|
||||
var columns = String.Join(",", values.Select(c => c.ToString()));
|
||||
|
||||
var command = new SQLiteCommand(string.Format("CREATE TABLE [{0}] ({1})", tableName, columns));
|
||||
command.Connection = _connection;
|
||||
ExecuteNonQuery("CREATE TABLE [{0}] ({1})", tableName, columns);
|
||||
|
||||
command.ExecuteNonQuery();
|
||||
foreach (var index in indexes)
|
||||
{
|
||||
ExecuteNonQuery("DROP INDEX {0}", index.IndexName);
|
||||
ExecuteNonQuery(index.CreateSql(tableName));
|
||||
}
|
||||
}
|
||||
|
||||
public void CopyData(string sourceTable, string destinationTable, IEnumerable<SQLiteColumn> columns)
|
||||
|
@ -128,6 +166,18 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
|
|||
}
|
||||
|
||||
|
||||
|
||||
private void ExecuteNonQuery(string command, params string[] args)
|
||||
{
|
||||
var sqLiteCommand = new SQLiteCommand(string.Format(command, args))
|
||||
{
|
||||
Connection = _connection
|
||||
};
|
||||
|
||||
sqLiteCommand.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
|
||||
public class SQLiteColumn
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
@ -138,6 +188,31 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
|
|||
return string.Format("[{0}] {1}", Name, Schema);
|
||||
}
|
||||
}
|
||||
|
||||
public class SQLiteIndex
|
||||
{
|
||||
public string Column { get; set; }
|
||||
public string Table { get; set; }
|
||||
public bool Unique { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("[{0}] Unique: {1}", Column, Unique);
|
||||
}
|
||||
|
||||
public string IndexName
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Format("IX_{0}_{1}", Table, Column);
|
||||
}
|
||||
}
|
||||
|
||||
public string CreateSql(string tableName)
|
||||
{
|
||||
return string.Format(@"CREATE UNIQUE INDEX ""{2}"" ON ""{0}"" (""{1}"" ASC)", tableName, Column, IndexName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -22,12 +22,14 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
|
|||
using (var transaction = _sqLiteMigrationHelper.BeginTransaction())
|
||||
{
|
||||
var originalColumns = _sqLiteMigrationHelper.GetColumns(tableName);
|
||||
var originalIndexes = _sqLiteMigrationHelper.GetIndexes(tableName);
|
||||
|
||||
var newColumns = originalColumns.Where(c => !columns.Contains(c.Key)).Select(c => c.Value).ToList();
|
||||
var newIndexes = originalIndexes.Where(c => !columns.Contains(c.Column));
|
||||
|
||||
var tempTableName = tableName + "_temp";
|
||||
|
||||
_sqLiteMigrationHelper.CreateTable(tempTableName, newColumns);
|
||||
_sqLiteMigrationHelper.CreateTable(tempTableName, newColumns, newIndexes);
|
||||
|
||||
_sqLiteMigrationHelper.CopyData(tableName, tempTableName, newColumns);
|
||||
|
||||
|
|
Loading…
Reference in New Issue