From 2068b732a20eaf798e25114037411cc1c3df7b69 Mon Sep 17 00:00:00 2001 From: "kay.one" Date: Sun, 1 Sep 2013 12:07:48 -0700 Subject: [PATCH] restore sqlite indexes on alter. --- .../Datastore/SQLiteMigrationHelperFixture.cs | 46 +++++++--- .../Framework/SQLiteMigrationHelper.cs | 91 +++++++++++++++++-- .../Migration/Framework/SqliteAlter.cs | 4 +- 3 files changed, 120 insertions(+), 21 deletions(-) diff --git a/NzbDrone.Core.Test/Datastore/SQLiteMigrationHelperFixture.cs b/NzbDrone.Core.Test/Datastore/SQLiteMigrationHelperFixture.cs index c940ac7b2..6f6dca730 100644 --- a/NzbDrone.Core.Test/Datastore/SQLiteMigrationHelperFixture.cs +++ b/NzbDrone.Core.Test/Datastore/SQLiteMigrationHelperFixture.cs @@ -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(); } - - [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()); 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()); _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()); _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); + } } } \ No newline at end of file diff --git a/NzbDrone.Core/Datastore/Migration/Framework/SQLiteMigrationHelper.cs b/NzbDrone.Core/Datastore/Migration/Framework/SQLiteMigrationHelper.cs index 80b4e25e8..3813c0e79 100644 --- a/NzbDrone.Core/Datastore/Migration/Framework/SQLiteMigrationHelper.cs +++ b/NzbDrone.Core/Datastore/Migration/Framework/SQLiteMigrationHelper.cs @@ -10,12 +10,12 @@ namespace NzbDrone.Core.Datastore.Migration.Framework public interface ISQLiteMigrationHelper { Dictionary GetColumns(string tableName); - void CreateTable(string tableName, IEnumerable values); + void CreateTable(string tableName, IEnumerable values, IEnumerable indexes); void CopyData(string sourceTable, string destinationTable, IEnumerable columns); - int GetRowCount(string tableName); void DropTable(string tableName); void RenameTable(string tableName, string newName); SQLiteTransaction BeginTransaction(); + List GetIndexes(string tableName); } public class SQLiteMigrationHelper : ISQLiteMigrationHelper @@ -25,7 +25,10 @@ namespace NzbDrone.Core.Datastore.Migration.Framework private static readonly Regex SchemaRegex = new Regex(@"['\""\[](?\w+)['\""\]]\s(?[\w-\s]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline); - public SQLiteMigrationHelper(IConnectionStringFactory connectionStringFactory,Logger logger) + private static readonly Regex IndexRegex = new Regex(@"\(""(?.*)""\s(?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 values) + public List 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(); + + while (reader.Read()) + { + sqls.Add(reader[0].ToString()); + } + + + var indexes = new List(); + + 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 values, IEnumerable 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 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); + } + } } diff --git a/NzbDrone.Core/Datastore/Migration/Framework/SqliteAlter.cs b/NzbDrone.Core/Datastore/Migration/Framework/SqliteAlter.cs index ce2372d69..572b0c493 100644 --- a/NzbDrone.Core/Datastore/Migration/Framework/SqliteAlter.cs +++ b/NzbDrone.Core/Datastore/Migration/Framework/SqliteAlter.cs @@ -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);