diff --git a/StackExchange.Profiling.Tests/SqlFormatterTest.cs b/StackExchange.Profiling.Tests/SqlFormatterTest.cs index a54925bb0..8e5ae7a3d 100644 --- a/StackExchange.Profiling.Tests/SqlFormatterTest.cs +++ b/StackExchange.Profiling.Tests/SqlFormatterTest.cs @@ -10,7 +10,9 @@ namespace StackExchange.Profiling.Tests [TestFixture] public class SqlFormatterTest { - private SqlServerFormatter _formatter; + private const string None = ""; + private const string At = "@"; + private SqlServerFormatter _formatter; private string _commandText; private SqlCommand _dbCommand; private static Dictionary _dbTypeMap; @@ -98,7 +100,7 @@ private static DbType GetDbType(Type type) } [Test] - public void EnsureVerboseSqlServerFormatterAddsOnlyInformation() + public void EnsureVerboseSqlServerFormatterOnlyAddsInformation() { // arrange // overwrite the formatter @@ -130,13 +132,13 @@ public void TabelQueryWithoutParameters() } [Test] - public void TableQueryWithOneParameters() + public void TableQueryWithOneParameters([Values(None, At)] string at) { // arrange _commandText = "select 1 from dbo.Table where x = @a"; const string expectedOutput = "DECLARE @a int = 123;\r\n\r\nselect 1 from dbo.Table where x = @a;"; CreateDbCommand(CommandType.Text); - AddDbParameter("a", 123); + AddDbParameter(at + "a", 123); // act var actualOutput = GenerateOutput(); @@ -146,14 +148,14 @@ public void TableQueryWithOneParameters() } [Test] - public void TableQueryWithTwoParameters() + public void TableQueryWithTwoParameters([Values(None, At)] string at) { // arrange _commandText = "select 1 from dbo.Table where x = @x, y = @y"; const string expectedOutput = "DECLARE @x int = 123,\r\n @y bigint = 123;\r\n\r\nselect 1 from dbo.Table where x = @x, y = @y;"; CreateDbCommand(CommandType.Text); - AddDbParameter("x", 123); - AddDbParameter("y", 123); + AddDbParameter(at + "x", 123); + AddDbParameter(at + "y", 123); // act var actualOutput = GenerateOutput(); @@ -178,13 +180,13 @@ public void StoredProcedureCallWithoutParameters() } [Test] - public void StoredProcedureCallWithOneParameter() + public void StoredProcedureCallWithOneParameter([Values(None, At)] string at) { // arrange _commandText = "dbo.SOMEPROCEDURE"; const string expectedOutput = "DECLARE @x int = 123;\r\n\r\nEXEC dbo.SOMEPROCEDURE @x = @x;"; CreateDbCommand(CommandType.StoredProcedure); - AddDbParameter("x", 123, ParameterDirection.Input); + AddDbParameter(at + "x", 123, ParameterDirection.Input); // act var actualOutput = GenerateOutput(); @@ -194,14 +196,14 @@ public void StoredProcedureCallWithOneParameter() } [Test] - public void StoredProcedureCallWithTwoParameter() + public void StoredProcedureCallWithTwoParameter([Values(None, At)] string at) { // arrange _commandText = "dbo.SOMEPROCEDURE"; const string expectedOutput = "DECLARE @x int = 123,\r\n @y bigint = 123;\r\n\r\nEXEC dbo.SOMEPROCEDURE @x = @x, @y = @y;"; CreateDbCommand(CommandType.StoredProcedure); - AddDbParameter("x", 123, ParameterDirection.Input); - AddDbParameter("y", 123, ParameterDirection.Input); + AddDbParameter(at + "x", 123, ParameterDirection.Input); + AddDbParameter(at + "y", 123, ParameterDirection.Input); // act var actualOutput = GenerateOutput(); @@ -211,13 +213,13 @@ public void StoredProcedureCallWithTwoParameter() } [Test] - public void StoredProcedureCallWithOneReturnParameter() + public void StoredProcedureCallWithOneReturnParameter([Values(None, At)] string at) { // arrange _commandText = "dbo.SOMEPROCEDURE"; const string expectedOutput = "DECLARE @retval int;\r\n\r\nEXEC @retval = dbo.SOMEPROCEDURE;\r\nSELECT @retval AS ReturnValue;"; CreateDbCommand(CommandType.StoredProcedure); - AddDbParameter("retval", null, ParameterDirection.ReturnValue); + AddDbParameter(at + "retval", null, ParameterDirection.ReturnValue); // act var actualOutput = GenerateOutput(); @@ -227,14 +229,14 @@ public void StoredProcedureCallWithOneReturnParameter() } [Test] - public void StoredProcedureCallWithNormalAndReturnParameter() + public void StoredProcedureCallWithNormalAndReturnParameter([Values(None, At)] string at) { // arrange _commandText = "dbo.SOMEPROCEDURE"; const string expectedOutput = "DECLARE @x int = 123,\r\n @retval int;\r\n\r\nEXEC @retval = dbo.SOMEPROCEDURE @x = @x;\r\nSELECT @retval AS ReturnValue;"; CreateDbCommand(CommandType.StoredProcedure); - AddDbParameter("x", 123, ParameterDirection.Input); - AddDbParameter("retval", null, ParameterDirection.ReturnValue); + AddDbParameter(at + "x", 123, ParameterDirection.Input); + AddDbParameter(at + "retval", null, ParameterDirection.ReturnValue); // act var actualOutput = GenerateOutput(); @@ -244,14 +246,14 @@ public void StoredProcedureCallWithNormalAndReturnParameter() } [Test] - public void StoredProcedureCallWithOneOutputParameter() + public void StoredProcedureCallWithOneOutputParameter([Values(None, At)] string at) { // arrange _commandText = "dbo.SOMEPROCEDURE"; const string expectedOutput = "DECLARE @x int = 123;\r\n\r\nEXEC dbo.SOMEPROCEDURE @x = @x OUTPUT;\r\nSELECT @x AS x;"; CreateDbCommand(CommandType.StoredProcedure); // note: since the sql-OUTPUT parameters can be read within the procedure, we need to support setting the value - AddDbParameter("x", 123, ParameterDirection.Output); + AddDbParameter(at + "x", 123, ParameterDirection.Output); // act var actualOutput = GenerateOutput(); @@ -261,15 +263,15 @@ public void StoredProcedureCallWithOneOutputParameter() } [Test] - public void StoredProcedureCallWithTwoOutputParameter() + public void StoredProcedureCallWithTwoOutputParameter([Values(None, At)] string at) { // arrange _commandText = "dbo.SOMEPROCEDURE"; const string expectedOutput = "DECLARE @x int = 123,\r\n @y int = 123;\r\n\r\nEXEC dbo.SOMEPROCEDURE @x = @x OUTPUT, @y = @y OUTPUT;\r\nSELECT @x AS x, @y AS y;"; CreateDbCommand(CommandType.StoredProcedure); // note: since the sql-OUTPUT parameters can be read within the procedure, we need to support setting the value - AddDbParameter("x", 123, ParameterDirection.Output); - AddDbParameter("y", 123, ParameterDirection.Output); + AddDbParameter(at + "x", 123, ParameterDirection.Output); + AddDbParameter(at + "y", 123, ParameterDirection.Output); // act var actualOutput = GenerateOutput(); @@ -279,15 +281,15 @@ public void StoredProcedureCallWithTwoOutputParameter() } [Test] - public void StoredProcedureCallWithOneOutputParameterAndOneReturnParameter() + public void StoredProcedureCallWithOneOutputParameterAndOneReturnParameter([Values(None, At)] string at) { // arrange _commandText = "dbo.SOMEPROCEDURE"; - string expectedOutput = "DECLARE @x int = 123,\r\n @retval int;\r\n\r\nEXEC @retval = dbo.SOMEPROCEDURE @x = @x OUTPUT;\r\nSELECT @retval AS ReturnValue, @x AS x;"; + const string expectedOutput = "DECLARE @x int = 123,\r\n @retval int;\r\n\r\nEXEC @retval = dbo.SOMEPROCEDURE @x = @x OUTPUT;\r\nSELECT @retval AS ReturnValue, @x AS x;"; CreateDbCommand(CommandType.StoredProcedure); // note: since the sql-OUTPUT parameters can be read within the procedure, we need to support setting the value - AddDbParameter("x", 123, ParameterDirection.Output); - AddDbParameter("retval", null, ParameterDirection.ReturnValue); + AddDbParameter(at + "x", 123, ParameterDirection.Output); + AddDbParameter(at + "retval", null, ParameterDirection.ReturnValue); // act var actualOutput = GenerateOutput(); @@ -297,14 +299,14 @@ public void StoredProcedureCallWithOneOutputParameterAndOneReturnParameter() } [Test] - public void StoredProcedureCallWithInOutputParameter() + public void StoredProcedureCallWithInOutputParameter([Values(None, At)] string at) { // arrange _commandText = "dbo.SOMEPROCEDURE"; const string expectedOutput = "DECLARE @x int = 123;\r\n\r\nEXEC dbo.SOMEPROCEDURE @x = @x OUTPUT;\r\nSELECT @x AS x;"; CreateDbCommand(CommandType.StoredProcedure); // note: since the sql-OUTPUT parameters can be read within the procedure, we need to support setting the value - AddDbParameter("x", 123, ParameterDirection.InputOutput); + AddDbParameter(at + "x", 123, ParameterDirection.InputOutput); // act var actualOutput = GenerateOutput(); diff --git a/StackExchange.Profiling/SqlFormatters/SqlServerFormatter.cs b/StackExchange.Profiling/SqlFormatters/SqlServerFormatter.cs index 53b8f6b7a..39165aaf6 100644 --- a/StackExchange.Profiling/SqlFormatters/SqlServerFormatter.cs +++ b/StackExchange.Profiling/SqlFormatters/SqlServerFormatter.cs @@ -86,14 +86,24 @@ public virtual string FormatSql(string commandText, List par return formattedText; } - private void GenerateStoreProcedureCall(string commandText, List parameters, StringBuilder buffer) + private string EnsureParameterPrefix(string name) + { + return !name.StartsWith("@") ? "@" + name : name; + } + + private string RemoveParameterPrefix(string name) + { + return name.StartsWith("@") ? name.Substring(1) : name; + } + + private void GenerateStoreProcedureCall(string commandText, List parameters, StringBuilder buffer) { buffer.Append("EXEC "); SqlTimingParameter returnValueParameter = GetReturnValueParameter(parameters); if (returnValueParameter != null) { - buffer.Append("@").Append(returnValueParameter.Name).Append(" = "); + buffer.Append(EnsureParameterPrefix(returnValueParameter.Name)).Append(" = "); } buffer.Append(commandText); @@ -111,14 +121,13 @@ private void GenerateSelectStatement(StringBuilder buffer, List x.Direction == ParameterDirection.InputOutput.ToString() || x.Direction == ParameterDirection.Output.ToString()) - .Select(x => x.Name.TrimStart('@')) - .Select(x => "@" + x + " AS " + x) + .Select(x => EnsureParameterPrefix(x.Name) + " AS " + RemoveParameterPrefix(x.Name)) .ToList(); var returnValueParameter = parameters.SingleOrDefault(x => x.Direction == ParameterDirection.ReturnValue.ToString()); if (returnValueParameter != null) { - parametersToSelect.Insert(0, "@" + returnValueParameter.Name + " AS ReturnValue"); + parametersToSelect.Insert(0, EnsureParameterPrefix(returnValueParameter.Name) + " AS ReturnValue"); } if (!parametersToSelect.Any()) return; @@ -163,7 +172,7 @@ private void GenerateStoredProcedureParameters(StringBuilder buffer, List