Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
updated to use latest build of EPPLUS dll. Tidied up help.
  • Loading branch information
Mitch-Wheat committed Dec 16, 2017
1 parent 839d572 commit 7593a88
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 72 deletions.
Binary file modified Libs/EPPlus.dll
Binary file not shown.
Binary file added Libs/_archive/EPPlus.dll
Binary file not shown.
26 changes: 15 additions & 11 deletions SQLDiagCmd/RunnerProxy.cs
Expand Up @@ -36,43 +36,47 @@ private sealed class Options : CommandLineOptionsBase
[Option("t", "timeout", HelpText = "Query timeout in seconds.", DefaultValue = 360)]
public int QueryTimeout { get; set; }

//[Option("S", "servername", Required = true, HelpText = "Server name or instance to run queries against.")]
//public string ServerName { get; set; }

[OptionList("S", "servers", Separator = ';', HelpText = "Semicolon separated list of Server names or instances to run queries against." +
" Separate each server/instance name with a semicolon." + " Do not include spaces between server names and semicolon.")]
" Separate each server/instance name with a semicolon." + " Do not include spaces.")]
[DefaultValue(null)]
public IList<string> Servers { get; set; }

[OptionList("d", "databases", Separator = ';', HelpText = "Semicolon separated list of specific databases to run database specific queries against." +
" Separate each database with a semicolon." + " Do not include spaces between databases and semicolon.")]
" Separate each database with a semicolon." + " Do not include spaces.")]
[DefaultValue(null)]
public IList<string> SpecificDatabases { get; set; }


[OptionList("x", "excludequeries", Separator = ';', HelpText = "Semicolon separated list of query numbers that should not be run." +
" Separate each number with a semicolon." + " Do not include spaces" + " Used to exclude long running queries (such as fragmention).")]
[DefaultValue(null)]
public IList<int> ExcludeQueryNumbers { get; set; }


[HelpOption]
public string GetUsage()
{
var help = new HelpText
{
Heading = "SQLDiagCmd",
Copyright = new CopyrightInfo("Mitch Wheat", 2012, 2018),
Copyright = new CopyrightInfo("Mitch Wheat", 2012, DateTime.Now.Year),
AdditionalNewLineAfterOption = true,
AddDashesToOption = true
};
HandleParsingErrorsInHelp(help);

help.AddPreOptionsLine("");
help.AddPreOptionsLine("");
help.AddPreOptionsLine("This is free software. You may redistribute copies of it under the terms of");
help.AddPreOptionsLine("the MIT License <http://www.opensource.org/licenses/mit-license.php>.");
help.AddPreOptionsLine("It uses EPPlus <http://epplus.codeplex.com/> and");
help.AddPreOptionsLine("the Command Line Parser Library <http://commandline.codeplex.com/>.");
help.AddPreOptionsLine("");
help.AddPreOptionsLine("Usage: SQLDiagCmd -E -S servername -i queries.sql -o C:\\outputfolder -d databaselist -A");
help.AddPreOptionsLine(" SQLDiagCmd -S servername -U username -P password -i queries.sql -o C:\\outputfolder -d databaselist");
help.AddPreOptionsLine(" SQLDiagCmd -E -S servername -i queries.sql -o C:\\outputfolder -A");
help.AddPreOptionsLine(" SQLDiagCmd -E -S serverlist -d databaselist -i queries.sql -o C:\\outputfolder -A");
help.AddPreOptionsLine("Usage:");
help.AddPreOptionsLine(" SQLDiagCmd -E -S servername -i queries.sql -o C:\\outputfolder -d databaselist -A");
help.AddPreOptionsLine(" SQLDiagCmd -S servername -U username -P password -i queries.sql -o C:\\outputfolder -d databaselist");
help.AddPreOptionsLine(" SQLDiagCmd -E -S servername -i queries.sql -o C:\\outputfolder -A");
help.AddPreOptionsLine(" SQLDiagCmd -E -S serverlist -d databaselist -i queries.sql -o C:\\outputfolder -A");
help.AddPreOptionsLine(" SQLDiagCmd -E -S server -d database -i 'SQL Server 2016 Diagnostic Information Queries.sql' -o C:\\output -A -x 37;65;66;71");
help.AddPreOptionsLine("");
help.AddPreOptionsLine("(serverlist and databaselist are semi-colon separated with no spaces)");
help.AddOptions(this);
Expand Down
Binary file modified SQLDiagCmd/SQLDiagRunner.dll
Binary file not shown.
6 changes: 3 additions & 3 deletions SQLDiagRunner/Properties/AssemblyInfo.cs
Expand Up @@ -12,7 +12,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SQLDiagRunner")]
[assembly: AssemblyCopyright("Copyright © Mitch Wheat 2013")]
[assembly: AssemblyCopyright("Copyright © Mitch Wheat 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

Expand All @@ -34,5 +34,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.4.13057")]
[assembly: AssemblyFileVersion("1.0.4.13057")]
[assembly: AssemblyVersion("1.0.5.17346")]
[assembly: AssemblyFileVersion("1.0.5.17346")]
85 changes: 52 additions & 33 deletions SQLDiagRunner/QueryFileParser.cs
@@ -1,16 +1,17 @@

using System.Collections.Generic;
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;

namespace SQLDiagRunner
{
public class QueryFileParser
{
private readonly string _filepath;
private const string PatternQueryStart = @"^--(.*)\(Query\s*\d*\)(\s*\((.*)\)|\s*.*)$";
private const string PatternQueryStart = @"^--(.*)\(Query\s*(\d*)\)(\s*\((.*)\)|\s*.*)$";
// 0 1 2 3
private const string EndOfServerWideQueriesMarker = "-- Database specific queries";

private readonly Regex _regexQueryStart = new Regex(PatternQueryStart, RegexOptions.Compiled|RegexOptions.IgnoreCase);
Expand All @@ -23,15 +24,13 @@ public QueryFileParser(string filepath)
public List<SqlQuery> Load()
{
if (!File.Exists(_filepath))
{
throw new FileNotFoundException(_filepath);
}

string[] queryText = File.ReadAllLines(_filepath);

int endLine = FindEndofServerWideQueries(queryText);

List<SqlQuery> result = Parse(queryText, 0, endLine, true);
var result = Parse(queryText, 0, endLine, true);
result.AddRange(Parse(queryText, endLine, queryText.Count() - 1, false));

return result;
Expand All @@ -52,73 +51,93 @@ private int FindEndofServerWideQueries(IEnumerable<string> queryAllLines)
return i - 1;
}

private List<SqlQuery> Parse(string[] queryAllLines, int startLine, int endLine, bool serverWide)
private List<SqlQuery> Parse(string[] queryLines, int startLine, int endLine, bool serverWide)
{
if (startLine >= endLine)
throw new System.ArgumentOutOfRangeException("startLine must be less than endline!");

var result = new List<SqlQuery>();
Match matchStart;

int i = startLine;

// skip any pre-amble
while (i < endLine)
do
{
Match matchStart = _regexQueryStart.Match(queryAllLines[i]);
matchStart = _regexQueryStart.Match(queryLines[i]);
if (matchStart.Success)
break;

i++;
}
} while (++i < endLine);

while (i < endLine)
{
string line = queryAllLines[i];
var query = new StringBuilder(queryAllLines[i]);
string line = queryLines[i];
var query = new StringBuilder(line);
query.AppendLine("");

string title = GetQueryTitle(line);
matchStart = _regexQueryStart.Match(queryLines[i]);

string title = GetQueryTitle(matchStart);
int number = GetQueryNumber(matchStart);

// End of query: readlines until next query is found or EOF
while (i < endLine)
{
i++;
line = queryAllLines[i];
line = queryLines[i];
Match matchEnd = _regexQueryStart.Match(line);
if (matchEnd.Success)
break;

query.AppendLine(line);
}

result.Add(new SqlQuery(query.ToString(), title, serverWide));
result.Add(new SqlQuery(query.ToString(), title, serverWide, number));
}

return result;
}

private string GetQueryTitle(string line)
private string GetQueryTitle(Match match)
{
Match match = _regexQueryStart.Match(line);
string title = line;
string result = "No Title Found";

if (match.Groups.Count > 2 && !string.IsNullOrEmpty(match.Groups[2].ToString().Trim()))
if (match.Groups.Count > 4)
{
string tmp = match.Groups[2].ToString().Trim();
int start = 0;
int len = tmp.Length;
if (tmp.StartsWith("("))
var tmp = match.Groups[4].ToString().Trim();
if (tmp.Length > 0)
{
start = 1;
len--;
result = tmp;
}
if (tmp.EndsWith(")"))
len--;
title = tmp.Substring(start, len);
}
else if (match.Groups.Count > 1)
else if (match.Groups.Count > 3)
{
title = match.Groups[1].ToString().Trim();
string tmp = match.Groups[3].ToString().Trim();
if (tmp.Length > 0)
{
result = tmp.RemoveStartAndEndChars("(", ")");
}
}

return title;
return result;
}

private int GetQueryNumber(Match match)
{
int result = 0;

if (match.Groups.Count > 2)
{
int tmp;

if (int.TryParse(match.Groups[2].ToString().Trim(), out tmp))
{
result = tmp;
}
}

return result;
}

}
}
32 changes: 9 additions & 23 deletions SQLDiagRunner/Runner.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;

Expand All @@ -11,7 +10,7 @@ namespace SQLDiagRunner
{
public class Runner
{
private readonly HashSet<string> _dictWorksheet = new HashSet<string>();
private readonly HashSet<string> _worksheetNames = new HashSet<string>();

public void ExecuteQueries
(
Expand All @@ -33,7 +32,7 @@ int queryTimeoutSeconds

foreach (var servername in servers)
{
_dictWorksheet.Clear();
_worksheetNames.Clear();

var outputFilepath = GetOutputFilepath(outputFolder, servername);

Expand All @@ -45,7 +44,7 @@ int queryTimeoutSeconds

ExecuteQueriesAndSaveToExcel(pck, connectionString, serverQueries, "", "", autoFitColumns, queryTimeoutSeconds);

// Not enough room in Excel WorkSheet names for the full database name, so prefix with DB number 1 to N.
// Not enough room in Excel WorkSheet tab names for the full database name, so prefix with DB number 1 to N.
int databaseNo = 1;
foreach (var db in databases)
{
Expand All @@ -55,8 +54,7 @@ int queryTimeoutSeconds


ExecuteQueriesAndSaveToExcel(pck, connectionString, dbQueries, db.Trim(),
databaseNo.ToString(CultureInfo.InvariantCulture),
autoFitColumns, queryTimeoutSeconds);
databaseNo.ToString(), autoFitColumns, queryTimeoutSeconds);
databaseNo++;
}

Expand Down Expand Up @@ -90,7 +88,7 @@ int queryTimeoutSeconds
{
foreach (var q in queries)
{
string query = GetQueryText(q, databaseName);
string query = q.GetQueryUseDBHelper(databaseName);
string worksheetName = GetWorkSheetName(q.Title, worksheetPrefix);
ExcelWorksheet ws = pck.Workbook.Worksheets.Add(worksheetName);

Expand All @@ -117,7 +115,7 @@ private void SaveDataTableToWorksheet(DataTable dt, ExcelWorksheet ws, bool auto

ws.Row(2).Style.Font.Bold = true;

// find datetime columns and set formatting
// find all datetime columns and set formatting
int numcols = dt.Columns.Count;
for (int i = 0; i < numcols; i++)
{
Expand All @@ -140,35 +138,23 @@ private void SaveDataTableToWorksheet(DataTable dt, ExcelWorksheet ws, bool auto

}

private string GetQueryText(SqlQuery q, string database)
{
return string.IsNullOrEmpty(database) ? q.QueryText : "USE [" + database + "] \r\n " + q.QueryText;
}

private string GetWorkSheetName(string queryTitle, string worksheetPrefix)
{
var worksheetName = string.IsNullOrEmpty(worksheetPrefix) ? queryTitle : worksheetPrefix + " " + queryTitle;

var worksheetNameSanitised = SanitiseWorkSheetName(worksheetName);
var worksheetNameSanitised = worksheetName.SanitiseWorkSheetName();

// Check if name already exists: 31 char limit for worksheet names!
while (_dictWorksheet.Contains(worksheetNameSanitised))
while (_worksheetNames.Contains(worksheetNameSanitised))
{
worksheetNameSanitised = worksheetNameSanitised.RandomiseLastNChars(3);
}

_dictWorksheet.Add(worksheetNameSanitised);
_worksheetNames.Add(worksheetNameSanitised);

return worksheetNameSanitised;
}

private static string SanitiseWorkSheetName(string wsname)
{
var s = wsname.RemoveInvalidExcelChars();

return s.Substring(0, Math.Min(31, s.Length));
}

private static string GetConnectionStringTemplate
(
string servername,
Expand Down
10 changes: 8 additions & 2 deletions SQLDiagRunner/SQLQuery.cs
Expand Up @@ -5,14 +5,20 @@ public class SqlQuery
{
public string QueryText { get; set; }
public string Title { get; set; }

public int QueryNumber { get; set; }
public bool ServerScope { get; set; }

public SqlQuery(string queryText, string title, bool serverScope)
public SqlQuery(string queryText, string title, bool serverScope, int queryNumber)
{
QueryText = queryText;
Title = title;
ServerScope = serverScope;
QueryNumber = queryNumber;
}

public string GetQueryUseDBHelper(string database)
{
return string.IsNullOrEmpty(database) ? QueryText : "USE [" + database + "] \r\n " + QueryText;
}
}
}
23 changes: 23 additions & 0 deletions SQLDiagRunner/StringExtensions.cs
Expand Up @@ -41,11 +41,34 @@ public static string RemoveInvalidExcelChars(this string s)
return s.Replace(invalidExcelChars, "");
}

public static string SanitiseWorkSheetName(this string s)
{
var wsname = s.RemoveInvalidExcelChars();

return wsname.Substring(0, Math.Min(31, wsname.Length));
}

public static string ReplaceInvalidFilenameChars(this string s, string newVal)
{
var invalidFilenameChars = Path.GetInvalidFileNameChars();

return s.Replace(invalidFilenameChars, newVal);
}

public static string RemoveStartAndEndChars(this string s, string startChar, string endChar)
{
int start = 0;
int len = s.Length;
if (s.StartsWith(startChar))
{
start = 1;
len--;
}
if (s.EndsWith(endChar))
len--;

return s.Substring(start, len);
}

}
}
Binary file modified SQLDiagRunnerUI/SQLDiagRunner.dll
Binary file not shown.

0 comments on commit 7593a88

Please sign in to comment.