Добавьте файлы проекта.
This commit is contained in:
123
SQLLinter/Infrastructure/Parser/SqlRuleVisitor.cs
Normal file
123
SQLLinter/Infrastructure/Parser/SqlRuleVisitor.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
using Microsoft.SqlServer.TransactSql.ScriptDom;
|
||||
using SQLLinter.Common;
|
||||
using SQLLinter.Core.Interfaces;
|
||||
using SQLLinter.Infrastructure.Configuration.Overrides;
|
||||
using SQLLinter.Infrastructure.Interfaces;
|
||||
using SQLLinter.Infrastructure.Rules.RuleExceptions;
|
||||
using SQLLinter.Infrastructure.Rules.RuleViolations;
|
||||
using System.Data;
|
||||
|
||||
namespace SQLLinter.Infrastructure.Parser;
|
||||
|
||||
public class SqlRuleVisitor : IRuleVisitor
|
||||
{
|
||||
private readonly IFragmentBuilder _fragmentBuilder;
|
||||
private readonly IReporter _reporter;
|
||||
private readonly ISqlStreamReaderBuilder _sqlStreamReaderBuilder;
|
||||
private readonly IPluginHandler _pluginHandler;
|
||||
|
||||
private readonly OverrideFinder _overrideFinder = new OverrideFinder();
|
||||
|
||||
public SqlRuleVisitor(IPluginHandler pluginHandler, IFragmentBuilder fragmentBuilder, IReporter reporter)
|
||||
: this(pluginHandler, fragmentBuilder, reporter, new SqlStreamReaderBuilder()) { }
|
||||
|
||||
public SqlRuleVisitor(IPluginHandler pluginHandler, IFragmentBuilder fragmentBuilder, IReporter reporter, ISqlStreamReaderBuilder sqlStreamReaderBuilder)
|
||||
{
|
||||
this._fragmentBuilder = fragmentBuilder;
|
||||
this._reporter = reporter;
|
||||
this._pluginHandler = pluginHandler;
|
||||
this._sqlStreamReaderBuilder = sqlStreamReaderBuilder;
|
||||
}
|
||||
|
||||
public void VisitRules(string sqlPath, IEnumerable<IRuleException> ignoredRules, Stream sqlFileStream)
|
||||
{
|
||||
var overrides = _overrideFinder.GetOverrideList(sqlFileStream);
|
||||
var overrideArray = overrides as IOverride[] ?? overrides.ToArray();
|
||||
|
||||
var sqlFragment = _fragmentBuilder.GetFragment(sqlPath, GetSqlTextReader(sqlFileStream), out var errors, overrideArray);
|
||||
|
||||
if (sqlFragment == null) return;
|
||||
|
||||
var ruleExceptions = ignoredRules as IRuleException[] ?? ignoredRules.ToArray();
|
||||
if (errors.Any())
|
||||
{
|
||||
HandleParserErrors(sqlPath, errors, ruleExceptions);
|
||||
}
|
||||
|
||||
var rules = _pluginHandler.Rules;
|
||||
foreach (var rule in rules)
|
||||
{
|
||||
VisitFragment(sqlFragment, rule, overrideArray, sqlPath);
|
||||
}
|
||||
}
|
||||
|
||||
private void VisitFragment(TSqlFragment sqlFragment, IRule rule, IEnumerable<IOverride> overrides, string filePath)
|
||||
{
|
||||
var violations = rule.Analyze(sqlFragment).ToList();
|
||||
|
||||
|
||||
if (!VisitorIsBlackListedForDynamicSql(rule))
|
||||
{
|
||||
var dynamicSqlVisitor = new DynamicSQLParser(DynamicSqlCallback);
|
||||
sqlFragment?.Accept(dynamicSqlVisitor);
|
||||
}
|
||||
|
||||
void DynamicSqlCallback(string dynamicSQL, int DynamicSqlStartLine, int DynamicSqlStartColumn)
|
||||
{
|
||||
rule.DynamicSqlStartLine = DynamicSqlStartLine;
|
||||
rule.DynamicSqlStartColumn = DynamicSqlStartColumn;
|
||||
|
||||
var dynamicSqlStream = ParsingUtility.GenerateStreamFromString(dynamicSQL);
|
||||
var dynamicFragment = _fragmentBuilder.GetFragment(filePath, GetSqlTextReader(dynamicSqlStream), out var errors, overrides);
|
||||
|
||||
if (dynamicFragment != null)
|
||||
{
|
||||
violations.AddRange(rule.Analyze(dynamicFragment));
|
||||
}
|
||||
}
|
||||
|
||||
violations.ForEach(t => _reporter.ReportViolation(filePath, t.Line, t.Column, rule.Severity, t.RuleName, t.Message));
|
||||
}
|
||||
|
||||
private static bool VisitorIsBlackListedForDynamicSql(IRule visitor)
|
||||
{
|
||||
return new List<string>
|
||||
{
|
||||
"SetAnsiNullsRule",
|
||||
"SetNoCountRule",
|
||||
"SetQuotedIdentifierRule",
|
||||
"SetTransactionIsolationLevelRule",
|
||||
"UnicodeStringRule"
|
||||
}.Any(x => visitor.GetType().ToString().Contains(x));
|
||||
}
|
||||
|
||||
private StreamReader GetSqlTextReader(Stream sqlFileStream)
|
||||
{
|
||||
return _sqlStreamReaderBuilder.CreateReader(sqlFileStream);
|
||||
}
|
||||
|
||||
private void HandleParserErrors(string sqlPath, IEnumerable<ParseError> errors, IEnumerable<IRuleException> ignoredRules)
|
||||
{
|
||||
var updatedExitCode = false;
|
||||
var ruleExceptions = ignoredRules as IRuleException[] ?? ignoredRules.ToArray();
|
||||
|
||||
foreach (var error in errors)
|
||||
{
|
||||
var globalRulesOnLine = ruleExceptions.OfType<GlobalRuleException>().Where(
|
||||
x => error.Line >= x.StartLine
|
||||
&& error.Line <= x.EndLine);
|
||||
|
||||
if (!globalRulesOnLine.Any())
|
||||
{
|
||||
_reporter.ReportViolation(new RuleViolation(sqlPath, "invalid-syntax", error.Message, error.Line, error.Column, RuleViolationSeverity.Critical));
|
||||
if (updatedExitCode)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
updatedExitCode = true;
|
||||
Environment.ExitCode = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user