Skip to content

Commit 24ffcea

Browse files
committed
Fixed scripting of TIME in Spreadsheet and SQL, and DATETIME2 in SQL
1 parent 675cef2 commit 24ffcea

10 files changed

+120
-37
lines changed

Code/TSqlFlex.Core.Tests/DataScriptingTests.cs

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -338,19 +338,10 @@ public void TIME_LowResolution_Data_ScriptsCorrectly()
338338
[Test()]
339339
public void TIME_HighResolution_Data_ScriptsCorrectly()
340340
{
341-
DateTime baseData = new DateTime(1900,1,1,2,33,44);
341+
TimeSpan baseData = new TimeSpan(TimeSpan.TicksPerHour * 2 + TimeSpan.TicksPerMinute * 33 + TimeSpan.TicksPerSecond * 44 + 1234567);
342342
object data = baseData;
343343
var fieldInfo = SchemaScriptingTests.FakeColumn("test", "test", 32, "time", false, 0, 0);
344-
Assert.AreEqual("'02:33:44'", FieldScripting.valueAsTSQLLiteral(data, fieldInfo), "time no fractional seconds");
345-
Assert.AreEqual("02:33:44", FieldScripting.formatTime(data, false), "time no fractional seconds");
346-
347-
baseData = new DateTime(1900, 1, 1, 2, 33, 44).AddMilliseconds(100);
348-
data = baseData;
349-
Assert.AreEqual("'02:33:44.1'", FieldScripting.valueAsTSQLLiteral(data, fieldInfo), "partial fractional seconds");
350-
Assert.AreEqual("02:33:44.1", FieldScripting.formatTime(data, false), "partial fractional seconds");
351-
352-
baseData = new DateTime(1900, 1, 1, 2, 33, 44).AddTicks(1234567);
353-
data = baseData;
344+
354345
Assert.AreEqual("'02:33:44.1234567'", FieldScripting.valueAsTSQLLiteral(data, fieldInfo), "time fractional seconds");
355346
Assert.AreEqual("02:33:44.1234567", FieldScripting.formatTime(data, false), "time fractional seconds");
356347
}
@@ -777,18 +768,15 @@ public void NULL_Data_ScriptsAsNull()
777768
[Test()]
778769
public void ReservedWord_IsScriptedWithBrackets()
779770
{
780-
781771
string fieldName = "Drop";
782772
var fieldInfo = SchemaScriptingTests.FakeColumn(fieldName, "test", 32, "int", false, 0, 0);
783773

784774
Assert.AreEqual("[Drop]", FieldScripting.FieldNameOrDefault(fieldInfo,0));
785-
786775
}
787776

788777
[Test()]
789778
public void FieldWithSpaces_IsScriptedWithBrackets()
790779
{
791-
792780
string fieldName = "What We Should Be Sending";
793781
var fieldInfo = SchemaScriptingTests.FakeColumn(fieldName, "test", 32, "int", false, 0, 0);
794782

@@ -798,7 +786,6 @@ public void FieldWithSpaces_IsScriptedWithBrackets()
798786
[Test()]
799787
public void FieldWithTab_IsScriptedWithBrackets()
800788
{
801-
802789
string fieldName = "This\tThat";
803790
var fieldInfo = SchemaScriptingTests.FakeColumn(fieldName, "test", 32, "int", false, 0, 0);
804791

@@ -808,7 +795,6 @@ public void FieldWithTab_IsScriptedWithBrackets()
808795
[Test()]
809796
public void FieldWithLineFeed_IsScriptedWithBrackets()
810797
{
811-
812798
string fieldName = "This\nis";
813799
var fieldInfo = SchemaScriptingTests.FakeColumn(fieldName, "test", 32, "int", false, 0, 0);
814800

@@ -818,7 +804,6 @@ public void FieldWithLineFeed_IsScriptedWithBrackets()
818804
[Test()]
819805
public void FieldWithOpenSquareBracket_IsScriptedWithBracketsButNotFurtherEscaped()
820806
{
821-
822807
string fieldName = "test[ing";
823808
var fieldInfo = SchemaScriptingTests.FakeColumn(fieldName, "test", 32, "int", false, 0, 0);
824809

@@ -828,7 +813,6 @@ public void FieldWithOpenSquareBracket_IsScriptedWithBracketsButNotFurtherEscape
828813
[Test()]
829814
public void FieldWithCloseSquareBracket_IsScriptedWithBracketsAndAlsoFurtherEscaped()
830815
{
831-
832816
string fieldName = "test]ing";
833817
var fieldInfo = SchemaScriptingTests.FakeColumn(fieldName, "test", 32, "int", false, 0, 0);
834818

@@ -838,7 +822,6 @@ public void FieldWithCloseSquareBracket_IsScriptedWithBracketsAndAlsoFurtherEsca
838822
[Test()]
839823
public void FieldWithCarriageReturn_IsScriptedWithBrackets()
840824
{
841-
842825
string fieldName = "Crazy\rtown";
843826
var fieldInfo = SchemaScriptingTests.FakeColumn(fieldName, "test", 32, "int", false, 0, 0);
844827

@@ -848,25 +831,21 @@ public void FieldWithCarriageReturn_IsScriptedWithBrackets()
848831
[Test()]
849832
public void NonReservedWord_IsScriptedWithoutBrackets()
850833
{
851-
852834
string fieldName = "TestColumnName";
853835
var fieldInfo = SchemaScriptingTests.FakeColumn(fieldName, "test", 32, "int", false, 0, 0);
854836

855837
Assert.AreEqual(false, TSqlRules.IsReservedWord(fieldName));
856838
Assert.AreEqual("TestColumnName", FieldScripting.FieldNameOrDefault(fieldInfo, 0));
857-
858839
}
859840

860841
[Test()]
861842
public void EmptyColumnName_IsScriptedAnonymously()
862843
{
863-
864844
string fieldName = "";
865845
var fieldInfo = SchemaScriptingTests.FakeColumn(fieldName, "test", 32, "int", false, 0, 0);
866846

867847
Assert.AreEqual(false, TSqlRules.IsReservedWord(fieldName));
868848
Assert.AreEqual("anonymousColumn1", FieldScripting.FieldNameOrDefault(fieldInfo, 0));
869-
870849
}
871850

872851
[Test()]

Code/TSqlFlex.Core.Tests/SchemaScriptingTests.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -318,16 +318,24 @@ public void DATETIME2_ScriptsCorrectly()
318318
FlexResultSet fsr = new FlexResultSet();
319319

320320
var dt = new List<SQLColumn>() {
321-
FakeColumn("DateTime2NotNull", "MyStuff", 8, "datetime2", false, 0, 0),
322-
FakeColumn("DateTime2Null", "MyStuff", 8, "datetime2", true, 0, 0)
321+
FakeColumn("DateTime2_0_NotNull", "MyStuff", 8, "datetime2", false, 0, 0),
322+
FakeColumn("DateTime2_0_Null", "MyStuff", 8, "datetime2", true, 0, 0),
323+
FakeColumn("DateTime2_3_NotNull", "MyStuff", 8, "datetime2", false, 0, 3),
324+
FakeColumn("DateTime2_3_Null", "MyStuff", 8, "datetime2", true, 0, 3),
325+
FakeColumn("DateTime2_7_NotNull", "MyStuff", 8, "datetime2", false, 0, 7),
326+
FakeColumn("DateTime2_7_Null", "MyStuff", 8, "datetime2", true, 0, 7)
323327
};
324328

325329
fsr.results.Add(new FlexResult());
326330
fsr.results[0].schema = dt;
327331

328332
var expected = @"CREATE TABLE MyTable(
329-
DateTime2NotNull datetime2 NOT NULL,
330-
DateTime2Null datetime2 NULL
333+
DateTime2_0_NotNull datetime2(0) NOT NULL,
334+
DateTime2_0_Null datetime2(0) NULL,
335+
DateTime2_3_NotNull datetime2(3) NOT NULL,
336+
DateTime2_3_Null datetime2(3) NULL,
337+
DateTime2_7_NotNull datetime2 NOT NULL,
338+
DateTime2_7_Null datetime2 NULL
331339
);
332340
";
333341
Assert.AreEqual(expected, fsr.ScriptResultAsCreateTable(0, "MyTable"));

Code/TSqlFlex.Core.Tests/TSqlFlex.Core.Tests.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,8 @@
3535
<SpecificVersion>False</SpecificVersion>
3636
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Microsoft SQL Server\110\SDK\Assemblies\Microsoft.SqlServer.Types.dll</HintPath>
3737
</Reference>
38-
<Reference Include="nunit.framework, Version=3.4.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
39-
<HintPath>..\packages\NUnit.3.4.1\lib\net35\nunit.framework.dll</HintPath>
40-
<Private>True</Private>
38+
<Reference Include="nunit.framework, Version=3.7.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
39+
<HintPath>..\packages\NUnit.3.7.1\lib\net35\nunit.framework.dll</HintPath>
4140
</Reference>
4241
<Reference Include="System" />
4342
<Reference Include="System.Core" />
@@ -57,6 +56,7 @@
5756
<Compile Include="SchemaScriptingTests.cs" />
5857
<Compile Include="Properties\AssemblyInfo.cs" />
5958
<Compile Include="TSqlRulesTests.cs" />
59+
<Compile Include="XmlSpreadsheetRenderTests.cs" />
6060
</ItemGroup>
6161
<ItemGroup>
6262
<ProjectReference Include="..\TSqlFlex.Core\TSqlFlex.Core.csproj">
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using NUnit.Framework;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Data.SqlClient;
5+
using System.Linq;
6+
using System.Text;
7+
using System.Xml;
8+
9+
namespace TSqlFlex.Core.Tests
10+
{
11+
[TestFixture()]
12+
public class XmlSpreadsheetRenderTests
13+
{
14+
[Test()]
15+
public void RenderingTimeField_RendersCorrectly()
16+
{
17+
var frs = new FlexResultSet();
18+
19+
var dt = new List<SQLColumn>() {
20+
SchemaScriptingTests.FakeColumn("ColIntNotNull", "MyStuff", 32, "int", false, 255, 255),
21+
SchemaScriptingTests.FakeColumn("ColIntNull", "MyStuff", 32, "int", true, 255, 255),
22+
SchemaScriptingTests.FakeColumn("ColTimeOfDay", "MyStuff", 32, "time", true, 255, 255)
23+
};
24+
25+
var result = new FlexResult() {
26+
schema = dt,
27+
data = new List<object[]>() {
28+
new object[] {99, 111, new TimeSpan(0, 00, 00, 00, 001)},
29+
new object[] {42, null, new TimeSpan(23,59,30)},
30+
}
31+
};
32+
33+
frs.results.Add(result);
34+
35+
var tempFileName = Guid.NewGuid().ToString() + ".txt";
36+
37+
var srp = new SqlRunParameters(new SqlConnectionStringBuilder(), "", SqlRunParameters.TO_XML_SPREADSHEET, tempFileName);
38+
39+
XmlSpreadsheetRenderer.renderAsXMLSpreadsheet(frs, srp);
40+
41+
var xmlSpreadsheetContent = srp.getOutputStreamAsString(tempFileName);
42+
43+
Assert.IsTrue(xmlSpreadsheetContent.Length > 1000, "expected more than 1000 characters of output");
44+
45+
Assert.IsTrue(xmlSpreadsheetContent.Contains(">99<"));
46+
Assert.IsTrue(xmlSpreadsheetContent.Contains(">111<"));
47+
Assert.IsTrue(xmlSpreadsheetContent.Contains(">1899-12-31T00:00:00.001<"));
48+
Assert.IsTrue(xmlSpreadsheetContent.Contains(">42<"));
49+
Assert.IsTrue(xmlSpreadsheetContent.Contains(">1899-12-31T23:59:30.000<"));
50+
51+
XmlDocument doc = null;
52+
53+
Assert.DoesNotThrow(() => {
54+
doc = new XmlDocument();
55+
doc.LoadXml(xmlSpreadsheetContent);
56+
}, "expected no exception");
57+
58+
Assert.IsNotNull(doc, "expected valid XML");
59+
}
60+
}
61+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<packages>
3-
<package id="NUnit" version="3.4.1" targetFramework="net35" />
3+
<package id="NUnit" version="3.7.1" targetFramework="net35" />
4+
<package id="NUnit3TestAdapter" version="3.7.0" targetFramework="net35" />
45
</packages>

Code/TSqlFlex.Core/FieldScripting.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ public static string DataTypeParameterIfAny(SQLColumn fieldInfo)
8383
}
8484
return "";
8585
}
86+
else if (fieldInfo.DataType == "datetime2")
87+
{
88+
if (fieldInfo.NumericScale < 7)
89+
{
90+
return $"({fieldInfo.NumericScale.ToString()})";
91+
}
92+
return "";
93+
}
8694
return "";
8795
}
8896

@@ -571,7 +579,8 @@ public static string formatTime(object data, bool forTSQLScript = true)
571579
if (data is TimeSpan)
572580
{
573581
TimeSpan t = (TimeSpan)data;
574-
if (t.Milliseconds == 0)
582+
long ticksAfterWholeSecond = t.Ticks - ((long)Math.Floor(t.TotalSeconds) * TimeSpan.TicksPerSecond);
583+
if (ticksAfterWholeSecond == 0)
575584
{
576585
return String.Format("{3}{0}:{1}:{2}{3}",
577586
t.Hours.ToString().PadLeft(2, '0'),
@@ -583,7 +592,7 @@ public static string formatTime(object data, bool forTSQLScript = true)
583592
t.Hours.ToString().PadLeft(2, '0'),
584593
t.Minutes.ToString().PadLeft(2, '0'),
585594
t.Seconds.ToString().PadLeft(2, '0'),
586-
t.Milliseconds.ToString().PadLeft(3, '0').TrimEnd('0'),
595+
ticksAfterWholeSecond.ToString().PadLeft(7,'0').TrimEnd('0'),
587596
quoting);
588597
}
589598
else if (data is DateTime)

Code/TSqlFlex.Core/Resources/XMLSpreadsheetTemplateHeader.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,7 @@
2424
<Style ss:ID="s64">
2525
<NumberFormat ss:Format="@"/>
2626
</Style>
27+
<Style ss:ID="s65">
28+
<NumberFormat ss:Format="Long Time"/>
29+
</Style>
2730
</Styles>

Code/TSqlFlex.Core/SqlRunParameters.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,18 @@ public SqlRunParameters(SqlConnectionStringBuilder csb, string sqlToRun, string
4444

4545
isolatedStore = Utils.getIsolatedStorageFile();
4646

47-
openNewOutputStream();
47+
openNewOutputStream(outputFileName);
4848
}
4949

5050
private string getNextFileName()
5151
{
5252
return "TSQLFlex_" + DateTime.UtcNow.ToString("yyyyMMddhhmmss.fffffff") + "_temp_" + outputFiles.Count + ".txt";
5353
}
5454

55-
public void openNewOutputStream()
55+
public void openNewOutputStream(string outputFileName = "")
5656
{
5757
flushAndCloseOutputStreamIfNeeded();
58-
this.currentFileName = getNextFileName();
58+
this.currentFileName = String.IsNullOrEmpty(outputFileName) ? getNextFileName() : outputFileName;
5959
outputFiles.Add(this.currentFileName);
6060

6161
Stream isoStream = new IsolatedStorageFileStream(this.currentFileName, FileMode.OpenOrCreate, FileAccess.Write, isolatedStore);
@@ -117,6 +117,15 @@ public void saveOutputStreamTo(string streamName, string saveAsFileName)
117117
isoStream.Close();
118118
}
119119

120+
public string getOutputStreamAsString(string streamName)
121+
{
122+
flushAndCloseOutputStreamIfNeeded();
123+
124+
var isoStream = new IsolatedStorageFileStream(streamName, FileMode.Open, FileAccess.Read, this.isolatedStore);
125+
var reader = new StreamReader(isoStream);
126+
return reader.ReadToEnd();
127+
}
128+
120129
//thanks! http://stackoverflow.com/questions/12970957/when-shall-i-do-a-explicity-flush-while-copying-streams-in-c
121130
public static void CopyStreamToEnd(Stream source, Stream destination)
122131
{

Code/TSqlFlex.Core/XmlSpreadsheetRenderer.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public static void renderAsXMLSpreadsheet(FlexResultSet resultSet, SqlRunParamet
5353
{
5454
srp.WriteToStream(String.Format("<Cell><Data ss:Type=\"Number\">{0}</Data></Cell>\r\n", escapeForXML(FieldScripting.valueAsTSQLLiteral(fieldData, fieldInfo, false))));
5555
}
56-
else if (fieldInfo.DataType == "date" || fieldInfo.DataType == "datetime2" || fieldInfo.DataType == "time" || fieldInfo.DataType == "datetime" ||
56+
else if (fieldInfo.DataType == "date" || fieldInfo.DataType == "datetime2" || fieldInfo.DataType == "datetime" ||
5757
fieldInfo.DataType == "smalldatetime")
5858
{
5959
srp.WriteToStream(String.Format("<Cell ss:StyleID=\"s63\"><Data ss:Type=\"DateTime\">{0}.{1}</Data></Cell>\r\n",
@@ -70,6 +70,15 @@ public static void renderAsXMLSpreadsheet(FlexResultSet resultSet, SqlRunParamet
7070
{
7171
srp.WriteToStream(String.Format("<Cell ss:StyleID=\"s64\"><Data ss:Type=\"String\">{0}</Data></Cell>\r\n", escapeForXML(FieldScripting.formatVarbinary(fieldData))));
7272
}
73+
else if (fieldInfo.DataType == "time")
74+
{
75+
srp.WriteToStream(String.Format("<Cell ss:StyleID=\"s65\"><Data ss:Type=\"DateTime\">1899-12-31T{0}:{1}:{2}.{3}</Data></Cell>\r\n",
76+
((TimeSpan)fieldData).Hours.ToString("00"),
77+
((TimeSpan)fieldData).Minutes.ToString("00"),
78+
((TimeSpan)fieldData).Seconds.ToString("00"),
79+
((TimeSpan)fieldData).Milliseconds.ToString("000")
80+
));
81+
}
7382
else
7483
{
7584
srp.WriteToStream(String.Format("<Cell ss:StyleID=\"s64\"><Data ss:Type=\"String\">{0}</Data></Cell>\r\n", escapeForXML(FieldScripting.valueAsTSQLLiteral(fieldData, fieldInfo, false))));

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ Follow the instructions [here](https://github.com/nycdotnet/TSqlFlex/blob/master
1818
Please either create issues on GitHub, or reach out to Steve on Twitter at [@nycdotnet](https://twitter.com/nycdotnet).
1919

2020
**Patch notes:**
21+
* v0.2.1-beta (2016-07-13):
22+
* Fixed scripting of TIME to XML Spreadsheet (no longer crashes)
23+
* Improved scripting of TIME to SQL scripts - can include up to 7 digits of scale.
24+
* Improved scripting of DATETIME2 to SQL scripts - now includes scale number if relevant.
2125
* v0.2.0-beta (2016-09-23):
2226
* Implemented new script as C# feature.
2327
* Many behind-the-scenes code improvements.

0 commit comments

Comments
 (0)