Skip to content

Commit

Permalink
fix #79
Browse files Browse the repository at this point in the history
  • Loading branch information
mgravell committed Nov 17, 2023
1 parent a5fba00 commit b622698
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 20 deletions.
43 changes: 25 additions & 18 deletions src/Dapper.AOT.Analyzers/SqlAnalysis/TSqlProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -755,33 +755,37 @@ public override void Visit(SelectStatement node)
}
index++;
}

if (reads != 0)
{
if (sets != 0)
{
parser.OnSelectAssignAndRead(spec);
}
bool firstQuery = AddQuery();
if (firstQuery && SingleRow // optionally enforce single-row validation
&& spec.FromClause is not null) // no "from" is things like 'select @id, @name' - always one row
if (node.Into is null) // otherwise not actually a query
{
bool haveTopOrFetch = false;
if (spec.TopRowFilter is { Percent: false, Expression: ScalarExpression top })
bool firstQuery = AddQuery();
if (firstQuery && SingleRow // optionally enforce single-row validation
&& spec.FromClause is not null) // no "from" is things like 'select @id, @name' - always one row
{
haveTopOrFetch = EnforceTop(top);
}
else if (spec.OffsetClause is { FetchExpression: ScalarExpression fetch })
{
haveTopOrFetch = EnforceTop(fetch);
}
bool haveTopOrFetch = false;
if (spec.TopRowFilter is { Percent: false, Expression: ScalarExpression top })
{
haveTopOrFetch = EnforceTop(top);
}
else if (spec.OffsetClause is { FetchExpression: ScalarExpression fetch })
{
haveTopOrFetch = EnforceTop(fetch);
}

// we want *either* a WHERE (which we will allow with/without a TOP),
// or a TOP + ORDER BY
if (!IsUnfiltered(spec.FromClause, spec.WhereClause)) { } // fine
else if (haveTopOrFetch && spec.OrderByClause is not null) { } // fine
else
{
parser.OnSelectSingleRowWithoutWhere(node);
// we want *either* a WHERE (which we will allow with/without a TOP),
// or a TOP + ORDER BY
if (!IsUnfiltered(spec.FromClause, spec.WhereClause)) { } // fine
else if (haveTopOrFetch && spec.OrderByClause is not null) { } // fine
else
{
parser.OnSelectSingleRowWithoutWhere(node);
}
}
}
}
Expand Down Expand Up @@ -1340,6 +1344,9 @@ public override void ExplicitVisit(BinaryExpression node)

public override void Visit(OutputClause node)
{
// note that this doesn't handle OUTPUT INTO,
// which is via OutputIntoClause

AddQuery(); // works like a query
base.Visit(node);
}
Expand Down
13 changes: 13 additions & 0 deletions test/Dapper.AOT.Test/Verifiers/DAP025.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,17 @@ exec SomeLookupFetch
Diagnostic(Diagnostics.ExecuteCommandWithQuery).WithLocation(0),
]);

[Fact]
public Task ReportWhenNoQueryExpected() => SqlVerifyAsync("""
SELECT [Test]
FROM MyTable
""", SqlAnalysis.SqlParseInputFlags.ExpectNoQuery,
Diagnostic(Diagnostics.ExecuteCommandWithQuery).WithLocation(Execute));

[Fact] // false positive scenario, https://github.com/DapperLib/DapperAOT/issues/79
public Task DoNotReportSelectInto() => SqlVerifyAsync("""
SELECT [Test]
INTO #MyTemporaryTable FROM MyTable
""", SqlAnalysis.SqlParseInputFlags.ExpectNoQuery);

}
13 changes: 13 additions & 0 deletions test/Dapper.AOT.Test/Verifiers/DAP026.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,17 @@ exec SomeLookupInsert 'North'
Diagnostic(Diagnostics.QueryCommandMissingQuery).WithLocation(0),
]);

[Fact]
public Task DoNotReportWhenQueryExpected() => SqlVerifyAsync("""
SELECT [Test]
FROM MyTable
""", SqlAnalysis.SqlParseInputFlags.ExpectQuery);

[Fact]
public Task ReportSelectInto() => SqlVerifyAsync("""
SELECT [Test]
INTO #MyTemporaryTable FROM MyTable
""", SqlAnalysis.SqlParseInputFlags.ExpectQuery,
Diagnostic(Diagnostics.QueryCommandMissingQuery).WithLocation(Execute));

}
6 changes: 4 additions & 2 deletions test/Dapper.AOT.Test/Verifiers/Verifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,9 @@ protected static Func<Solution, ProjectId, Solution> WithVisualBasicParseOptions
{
internal Task SqlVerifyAsync(string sql,
params DiagnosticResult[] expected) => SqlVerifyAsync(sql, SqlParseInputFlags.None, expected);


public const int Execute = 9999;

internal Task SqlVerifyAsync(string sql, SqlParseInputFlags sqlParseInputFlags, params DiagnosticResult[] expected)
{
var cs = $$"""
Expand All @@ -182,7 +184,7 @@ internal Task SqlVerifyAsync(string sql, SqlParseInputFlags sqlParseInputFlags,
[DapperAot(false)]
class SomeCode
{
public void Foo(DbConnection conn) => conn.Execute(@"{{sql.Replace("\"", "\"\"")}}");
public void Foo(DbConnection conn) => conn.{|#{{Execute}}:Execute|}(@"{{sql.Replace("\"", "\"\"")}}");
}
""";
return CSVerifyAsync(cs, DefaultConfig, expected, SqlSyntax.SqlServer, sqlParseInputFlags | SqlParseInputFlags.DebugMode);
Expand Down

0 comments on commit b622698

Please sign in to comment.