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 FluentAssertions;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||||
|
@ -18,8 +19,6 @@ namespace NzbDrone.Core.Test.Datastore
|
||||||
_subject = Mocker.Resolve<SQLiteMigrationHelper>();
|
_subject = Mocker.Resolve<SQLiteMigrationHelper>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_parse_existing_columns()
|
public void should_parse_existing_columns()
|
||||||
{
|
{
|
||||||
|
@ -37,7 +36,7 @@ namespace NzbDrone.Core.Test.Datastore
|
||||||
var columns = _subject.GetColumns("Series");
|
var columns = _subject.GetColumns("Series");
|
||||||
columns.Remove("Title");
|
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");
|
var newColumns = _subject.GetColumns("Series_New");
|
||||||
|
|
||||||
|
@ -45,12 +44,6 @@ namespace NzbDrone.Core.Test.Datastore
|
||||||
newColumns.Should().NotContainKey("Title");
|
newColumns.Should().NotContainKey("Title");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_get_zero_count_on_empty_table()
|
|
||||||
{
|
|
||||||
_subject.GetRowCount("Series").Should().Be(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_be_able_to_transfer_empty_tables()
|
public void should_be_able_to_transfer_empty_tables()
|
||||||
|
@ -58,7 +51,7 @@ namespace NzbDrone.Core.Test.Datastore
|
||||||
var columns = _subject.GetColumns("Series");
|
var columns = _subject.GetColumns("Series");
|
||||||
columns.Remove("Title");
|
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);
|
_subject.CopyData("Series", "Series_New", columns.Values);
|
||||||
|
@ -74,11 +67,40 @@ namespace NzbDrone.Core.Test.Datastore
|
||||||
var columns = _subject.GetColumns("Episodes");
|
var columns = _subject.GetColumns("Episodes");
|
||||||
columns.Remove("Title");
|
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.CopyData("Episodes", "Episodes_New", columns.Values);
|
||||||
|
|
||||||
_subject.GetRowCount("Episodes_New").Should().Be(originalEpisodes.Count);
|
_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
|
public interface ISQLiteMigrationHelper
|
||||||
{
|
{
|
||||||
Dictionary<String, SQLiteMigrationHelper.SQLiteColumn> GetColumns(string tableName);
|
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);
|
void CopyData(string sourceTable, string destinationTable, IEnumerable<SQLiteMigrationHelper.SQLiteColumn> columns);
|
||||||
int GetRowCount(string tableName);
|
|
||||||
void DropTable(string tableName);
|
void DropTable(string tableName);
|
||||||
void RenameTable(string tableName, string newName);
|
void RenameTable(string tableName, string newName);
|
||||||
SQLiteTransaction BeginTransaction();
|
SQLiteTransaction BeginTransaction();
|
||||||
|
List<SQLiteMigrationHelper.SQLiteIndex> GetIndexes(string tableName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SQLiteMigrationHelper : ISQLiteMigrationHelper
|
public class SQLiteMigrationHelper : ISQLiteMigrationHelper
|
||||||
|
@ -25,7 +25,10 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
|
||||||
private static readonly Regex SchemaRegex = new Regex(@"['\""\[](?<name>\w+)['\""\]]\s(?<schema>[\w-\s]+)",
|
private static readonly Regex SchemaRegex = new Regex(@"['\""\[](?<name>\w+)['\""\]]\s(?<schema>[\w-\s]+)",
|
||||||
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||||||
|
|
||||||
public SQLiteMigrationHelper(IConnectionStringFactory connectionStringFactory,Logger logger)
|
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
|
try
|
||||||
{
|
{
|
||||||
|
@ -34,7 +37,7 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
logger.ErrorException("Couldn't open databse " + connectionStringFactory.MainDbConnectionString, e);
|
logger.ErrorException("Couldn't open database " + connectionStringFactory.MainDbConnectionString, e);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +50,7 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
|
||||||
tableName));
|
tableName));
|
||||||
|
|
||||||
command.Connection = _connection;
|
command.Connection = _connection;
|
||||||
|
|
||||||
return (string)command.ExecuteScalar();
|
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 columns = String.Join(",", values.Select(c => c.ToString()));
|
||||||
|
|
||||||
var command = new SQLiteCommand(string.Format("CREATE TABLE [{0}] ({1})", tableName, columns));
|
ExecuteNonQuery("CREATE TABLE [{0}] ({1})", tableName, columns);
|
||||||
command.Connection = _connection;
|
|
||||||
|
|
||||||
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)
|
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 class SQLiteColumn
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
@ -138,6 +188,31 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
|
||||||
return string.Format("[{0}] {1}", Name, Schema);
|
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())
|
using (var transaction = _sqLiteMigrationHelper.BeginTransaction())
|
||||||
{
|
{
|
||||||
var originalColumns = _sqLiteMigrationHelper.GetColumns(tableName);
|
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 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";
|
var tempTableName = tableName + "_temp";
|
||||||
|
|
||||||
_sqLiteMigrationHelper.CreateTable(tempTableName, newColumns);
|
_sqLiteMigrationHelper.CreateTable(tempTableName, newColumns, newIndexes);
|
||||||
|
|
||||||
_sqLiteMigrationHelper.CopyData(tableName, tempTableName, newColumns);
|
_sqLiteMigrationHelper.CopyData(tableName, tempTableName, newColumns);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue