Skip to content

Commit

Permalink
Fix columnstore indexes not working
Browse files Browse the repository at this point in the history
  • Loading branch information
sethreno committed Feb 8, 2017
1 parent 5be7540 commit 91f1e90
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 31 deletions.
12 changes: 4 additions & 8 deletions model/Models/Constraint.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using System.Collections.Generic;
using System.Linq;
using SchemaZen.Library.Extensions;

namespace SchemaZen.Library.Models {
public class Constraint : INameable, IScriptable {
public bool Clustered { get; set; }
public bool ColumnStore { get; set; }
public string IndexType { get; set; }
public List<ConstraintColumn> Columns { get; set; } = new List<ConstraintColumn>();
public List<string> IncludedColumns { get; set; } = new List<string>();
public string Name { get; set; }
Expand All @@ -31,10 +31,6 @@ public static Constraint CreateCheckedConstraint(string name, bool isNotForRepli
return constraint;
}

public string ColumnStoreText => !ColumnStore ? "" : " COLUMNSTORE";

public string ClusteredText => !Clustered ? "NONCLUSTERED" : "CLUSTERED";

public string UniqueText => Type != " PRIMARY KEY" && !Unique ? "" : " UNIQUE";

public string ScriptCreate() {
Expand All @@ -43,7 +39,7 @@ public string ScriptCreate() {
var notForReplicationOption = _isNotForReplication ? "NOT FOR REPLICATION" : "";
return $"CONSTRAINT [{Name}] CHECK {notForReplicationOption} {_checkConstraintExpression}";
case "INDEX":
var sql = $"CREATE{UniqueText} {ClusteredText}{ColumnStoreText} INDEX [{Name}] ON [{Table.Owner}].[{Table.Name}] ({string.Join(", ", Columns.Select(c => c.Script()).ToArray())})";
var sql = $"CREATE{UniqueText}{IndexType.Space()} INDEX [{Name}] ON [{Table.Owner}].[{Table.Name}] ({string.Join(", ", Columns.Select(c => c.Script()).ToArray())})";
if (IncludedColumns.Count > 0) {
sql += $" INCLUDE ([{string.Join("], [", IncludedColumns.ToArray())}])";
}
Expand All @@ -53,7 +49,7 @@ public string ScriptCreate() {
return sql;
}

return (Table.IsType ? string.Empty : $"CONSTRAINT [{Name}] ") + $"{Type} {ClusteredText} ({string.Join(", ", Columns.Select(c => c.Script()).ToArray())})";
return (Table.IsType ? string.Empty : $"CONSTRAINT [{Name}] ") + $"{Type}{IndexType.Space()} ({string.Join(", ", Columns.Select(c => c.Script()).ToArray())})";
}
}
}
8 changes: 4 additions & 4 deletions model/Models/Database.cs
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,8 @@ private void LoadConstraintsAndIndexes(SqlCommand cm) {
i.type_desc,
i.filter_definition,
isnull(ic.is_included_column, 0) as is_included_column,
ic.is_descending_key
ic.is_descending_key,
i.type
from (
select object_id, name, schema_id, 'T' as baseType
from sys.tables
Expand Down Expand Up @@ -633,10 +634,9 @@ from sys.table_types
ViewIndexes.Add(c);
}
}
c.Clustered = (string)dr["type_desc"] == "CLUSTERED";
c.IndexType = dr["type_desc"] as string;
c.Unique = (bool)dr["is_unique"];
var filter = dr["filter_definition"].ToString(); //can be null
c.Filter = filter;
c.Filter = dr["filter_definition"] as string;
if ((bool)dr["is_included_column"]) {
c.IncludedColumns.Add((string)dr["columnName"]);
} else {
Expand Down
1 change: 1 addition & 0 deletions model/Schemazen.Library.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
<Compile Include="Models\SqlUser.cs" />
<Compile Include="Models\Synonym.cs" />
<Compile Include="Models\Table.cs" />
<Compile Include="StringUtil.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Schemazen.Library.nuspec" />
Expand Down
29 changes: 29 additions & 0 deletions model/StringUtil.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;

namespace SchemaZen.Library {

public class StringUtil {

/// <summary>
/// Adds a space to the beginning of a string.
/// If the string is null or empty it's returned as-is
/// </summary>
public static string AddSpaceIfNotEmpty(string val) {
if (String.IsNullOrEmpty(val)) return val;
return $" {val}";
}
}

namespace Extensions {

/// <summary>
/// Extension methods to make sql script generators more readable.
/// </summary>
public static class Strings {

public static string Space(this String val) {
return StringUtil.AddSpaceIfNotEmpty(val);
}
}
}
}
19 changes: 15 additions & 4 deletions test/ConstraintTester.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ private static Constraint SetUp() {
[Test]
public void clustered_index() {
var c = SetUp();
c.Clustered = true;
c.IndexType = "CLUSTERED";
Assert.AreEqual(
"CREATE CLUSTERED INDEX [test] ON [dbo].[test] ([a], [b])",
c.ScriptCreate());
Expand All @@ -27,16 +27,25 @@ public void clustered_index() {
[Test]
public void nonclustered_index() {
var c = SetUp();
c.Clustered = false;
c.IndexType = "NONCLUSTERED";
Assert.AreEqual(
"CREATE NONCLUSTERED INDEX [test] ON [dbo].[test] ([a], [b])",
c.ScriptCreate());
}

[Test]
public void columnstore_index() {
public void clustered_columnstore_index() {
var c = SetUp();
c.ColumnStore = true;
c.IndexType = "CLUSTERED COLUMNSTORE";
Assert.AreEqual(
"CREATE CLUSTERED COLUMNSTORE INDEX [test] ON [dbo].[test] ([a], [b])",
c.ScriptCreate());
}

[Test]
public void nonclustered_columnstore_index() {
var c = SetUp();
c.IndexType = "NONCLUSTERED COLUMNSTORE";
Assert.AreEqual(
"CREATE NONCLUSTERED COLUMNSTORE INDEX [test] ON [dbo].[test] ([a], [b])",
c.ScriptCreate());
Expand All @@ -46,6 +55,7 @@ public void columnstore_index() {
public void primary_key() {
var c = SetUp();
c.Type = "PRIMARY KEY";
c.IndexType = "NONCLUSTERED";
Assert.AreEqual(
"CONSTRAINT [test] PRIMARY KEY NONCLUSTERED ([a], [b])",
c.ScriptCreate());
Expand All @@ -55,6 +65,7 @@ public void primary_key() {
public void foreign_key() {
var c = SetUp();
c.Type = "FOREIGN KEY";
c.IndexType = "NONCLUSTERED";
Assert.AreEqual(
"CONSTRAINT [test] FOREIGN KEY NONCLUSTERED ([a], [b])",
c.ScriptCreate());
Expand Down
48 changes: 35 additions & 13 deletions test/DatabaseTester.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,16 +209,20 @@ public void TestScript() {
var t1 = new Table("dbo", "t1");
t1.Columns.Add(new Column("col1", "int", false, null) { Position = 1 });
t1.Columns.Add(new Column("col2", "int", false, null) { Position = 2 });
t1.AddConstraint(new Constraint("pk_t1", "PRIMARY KEY", "col1,col2"));
t1.FindConstraint("pk_t1").Clustered = true;
t1.AddConstraint(new Constraint("pk_t1", "PRIMARY KEY", "col1,col2") {
IndexType = "CLUSTERED"
});

var t2 = new Table("dbo", "t2");
t2.Columns.Add(new Column("col1", "int", false, null) { Position = 1 });
t2.Columns.Add(new Column("col2", "int", false, null) { Position = 2 });
t2.Columns.Add(new Column("col3", "int", false, null) { Position = 3 });
t2.AddConstraint(new Constraint("pk_t2", "PRIMARY KEY", "col1"));
t2.FindConstraint("pk_t2").Clustered = true;
t2.AddConstraint(new Constraint("IX_col3", "UNIQUE", "col3"));
t2.AddConstraint(new Constraint("pk_t2", "PRIMARY KEY", "col1") {
IndexType = "CLUSTERED"
});
t2.AddConstraint(new Constraint("IX_col3", "UNIQUE", "col3") {
IndexType = "NONCLUSTERED"
});

db.ForeignKeys.Add(new ForeignKey(t2, "fk_t2_t1", "col2,col3", t1, "col1,col2"));

Expand All @@ -236,8 +240,9 @@ public void TestScript() {
TestHelper.DropDb("TEST_TEMP");

foreach (var t in db.Tables) {
Assert.IsNotNull(db2.FindTable(t.Name, t.Owner));
Assert.IsFalse(db2.FindTable(t.Name, t.Owner).Compare(t).IsDiff);
var copy = db2.FindTable(t.Name, t.Owner);
Assert.IsNotNull(copy);
Assert.IsFalse(copy.Compare(t).IsDiff);
}
}

Expand Down Expand Up @@ -489,31 +494,46 @@ public void TestScriptToDir() {
var policy = new Table("dbo", "Policy");
policy.Columns.Add(new Column("id", "int", false, null) { Position = 1 });
policy.Columns.Add(new Column("form", "tinyint", false, null) { Position = 2 });
policy.AddConstraint(new Constraint("PK_Policy", "PRIMARY KEY", "id") { Clustered = true, Unique = true });
policy.AddConstraint(new Constraint("PK_Policy", "PRIMARY KEY", "id") {
IndexType = "CLUSTERED",
Unique = true
});
policy.Columns.Items[0].Identity = new Identity(1, 1);

var loc = new Table("dbo", "Location");
loc.Columns.Add(new Column("id", "int", false, null) { Position = 1 });
loc.Columns.Add(new Column("policyId", "int", false, null) { Position = 2 });
loc.Columns.Add(new Column("storage", "bit", false, null) { Position = 3 });
loc.Columns.Add(new Column("category", "int", false, null) { Position = 4 });
loc.AddConstraint(new Constraint("PK_Location", "PRIMARY KEY", "id") { Clustered = true, Unique = true });
loc.AddConstraint(new Constraint("PK_Location", "PRIMARY KEY", "id") {
IndexType = "CLUSTERED",
Unique = true
});
loc.Columns.Items[0].Identity = new Identity(1, 1);

var formType = new Table("dbo", "FormType");
formType.Columns.Add(new Column("code", "tinyint", false, null) { Position = 1 });
formType.Columns.Add(new Column("desc", "varchar", 10, false, null) { Position = 2 });
formType.AddConstraint(new Constraint("PK_FormType", "PRIMARY KEY", "code") { Clustered = true, Unique = true });
formType.AddConstraint(new Constraint("PK_FormType", "PRIMARY KEY", "code") {
IndexType = "CLUSTERED",
Unique = true
});
formType.AddConstraint(Constraint.CreateCheckedConstraint("CK_FormType", false, "([code]<(5))"));

var categoryType = new Table("dbo", "CategoryType");
categoryType.Columns.Add(new Column("id", "int", false, null) { Position = 1 });
categoryType.Columns.Add(new Column("Category", "varchar", 10, false, null) { Position = 2 });
categoryType.AddConstraint(new Constraint("PK_CategoryType", "PRIMARY KEY", "id") { Clustered = true, Unique = true });
categoryType.AddConstraint(new Constraint("PK_CategoryType", "PRIMARY KEY", "id") {
IndexType = "CLUSTERED",
Unique = true
});

var emptyTable = new Table("dbo", "EmptyTable");
emptyTable.Columns.Add(new Column("code", "tinyint", false, null) { Position = 1 });
emptyTable.AddConstraint(new Constraint("PK_EmptyTable", "PRIMARY KEY", "code") { Clustered = true, Unique = true });
emptyTable.AddConstraint(new Constraint("PK_EmptyTable", "PRIMARY KEY", "code") {
IndexType = "CLUSTERED",
Unique = true
});

var fk_policy_formType = new ForeignKey("FK_Policy_FormType");
fk_policy_formType.Table = policy;
Expand Down Expand Up @@ -543,7 +563,9 @@ public void TestScriptToDir() {
tt_codedesc.IsType = true;
tt_codedesc.Columns.Add(new Column("code", "tinyint", false, null) { Position = 1 });
tt_codedesc.Columns.Add(new Column("desc", "varchar", 10, false, null) { Position = 2 });
tt_codedesc.AddConstraint(new Constraint("PK_CodeDesc", "PRIMARY KEY", "code"));
tt_codedesc.AddConstraint(new Constraint("PK_CodeDesc", "PRIMARY KEY", "code") {
IndexType = "NONCLUSTERED"
});

var db = new Database("ScriptToDirTest");
db.Tables.Add(policy);
Expand Down
11 changes: 9 additions & 2 deletions test/TableTester.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,15 @@ 3 F Frozen
public void TestLargeAmountOfRowsImportAndExport() {
var t = new Table("dbo", "TestData");
t.Columns.Add(new Column("test_field", "int", false, null));
t.AddConstraint(new Constraint("PK_TestData", "PRIMARY KEY", "test_field"));
t.AddConstraint(new Constraint("IX_TestData_PK", "INDEX", "test_field") { Clustered = true, Table = t, Unique = true }); // clustered index is required to ensure the row order is the same as what we import
t.AddConstraint(new Constraint("PK_TestData", "PRIMARY KEY", "test_field") {
IndexType = "NONCLUSTERED"
});
t.AddConstraint(new Constraint("IX_TestData_PK", "INDEX", "test_field") {
// clustered index is required to ensure the row order is the same as what we import
IndexType = "CLUSTERED",
Table = t,
Unique = true
});

var conn = TestHelper.GetConnString("TESTDB");
DBHelper.DropDb(conn);
Expand Down

0 comments on commit 91f1e90

Please sign in to comment.