How can I validate sql scripts before executing them using .net 2.0 and c#?
If the sql is not valid I want to return error rows.
I know that the question was about .NET 2.0, but it may be interesting for someone. Validation of queries has slightly changed in the latest versions of Microsoft SQL Server.
The namespace is Microsoft.SqlServer.TransactSql.ScriptDom
instead of Microsoft.Data.Schema.ScriptDom
.
Where to find this library?
Path to the library is %programfiles(x86)%\Microsoft SQL Server\120\SDK\Assemblies
If you cannot find this library and Microsoft SQL Server is installed, try to change from 120
to 110
or 100
and use the corresponding parser (TSql110Parser
or TSql100Parser
respectively).
How to use?
I have two extensions: the first extension checks whether the input string is a valid SQL query and the second can be used to get errors from parsing.
using Microsoft.SqlServer.TransactSql.ScriptDom;
using System.Collections.Generic;
using System.IO;
using System.Linq;
public static class SqlStringExtensions
{
public static bool IsValidSql(this string str)
{
return !str.ValidateSql().Any();
}
public static IEnumerable ValidateSql(this string str)
{
if (string.IsNullOrWhiteSpace(str))
{
return new[] { "SQL query should be non empty." };
}
var parser = new TSql120Parser(false);
IList errors;
using (var reader = new StringReader(str))
{
parser.Parse(reader, out errors);
}
return errors.Select(err => err.Message);
}
}
Additionaly, I check that the input SQL query is not null or empty, because the parser thinks that empty string is perfectly valid (and I don't judge it).
How to test?
There are three NUnit tests which show how you can use this extensions.
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
[TestFixture]
public class SqlStringExtensionsTests
{
[Test]
public void ValidateSql_InvalidSql_ReturnsErrorMessages()
{
// this example doesn't contain "," between the field names
string invalidSql = "SELECT /*comment*/ " +
"CustomerID AS ID CustomerNumber FROM Customers";
IEnumerable results = invalidSql.ValidateSql();
Assert.AreNotEqual(0, results.Count());
}
[Test]
public void IsValidSql_ValidSql_ReturnsTrue()
{
string validSql = "SELECT /*comment*/ " +
"CustomerID AS ID, CustomerNumber FROM Customers";
bool result = validSql.IsValidSql();
Assert.AreEqual(true, result);
}
[Test]
public void IsValidSql_InvalidSql_ReturnsFalse()
{
// this example doesn't contain "," between the field names
string invalidSql = "SELECT /*comment*/ "+
" CustomerID AS ID CustomerNumber FROM Customers";
bool result = invalidSql.IsValidSql();
Assert.AreEqual(false, result);
}
}