88 lines
3.2 KiB
C#
88 lines
3.2 KiB
C#
using Microsoft.SqlServer.TransactSql.ScriptDom;
|
||
using SQLLinter.Common;
|
||
using SQLLinter.Common.Helpers;
|
||
|
||
namespace SQLLinter.Infrastructure.Rules;
|
||
|
||
public class ProcedureLoggingRule : BaseRuleVisitor
|
||
{
|
||
public override string Text => "В процедурах обязательно логирование (@DebugLog, LABEL_FINISH): {0}";
|
||
|
||
public override void Visit(CreateProcedureStatement node) => check(node, SQLHelpers.ObjectGetFullName(node.ProcedureReference.Name));
|
||
public override void Visit(CreateOrAlterProcedureStatement node) => check(node, SQLHelpers.ObjectGetFullName(node.ProcedureReference.Name));
|
||
public override void Visit(AlterProcedureStatement node) => check(node, SQLHelpers.ObjectGetFullName(node.ProcedureReference.Name));
|
||
|
||
private void check(ProcedureStatementBody node, string name)
|
||
{
|
||
var tokens = node.ScriptTokenStream;
|
||
|
||
bool hasDebugLog = false;
|
||
bool hasLabelFinish = false;
|
||
|
||
foreach (var token in tokens)
|
||
{
|
||
if (token.Text is null) continue;
|
||
|
||
if (token.Text.Equals("@DebugLog", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
hasDebugLog = true;
|
||
}
|
||
else if (token.Text.Equals("LABEL_FINISH:", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
hasLabelFinish = true;
|
||
}
|
||
}
|
||
|
||
if (!hasDebugLog || !hasLabelFinish)
|
||
{
|
||
AddViolation(node.ProcedureReference.Name, name);
|
||
}
|
||
}
|
||
}
|
||
|
||
public class ProcedureLoggingReturnRule : BaseRuleVisitor
|
||
{
|
||
public override string Text => "В процедурах с логированием RETURN запрещён: {0}";
|
||
|
||
public override void Visit(CreateProcedureStatement node) => check(node, SQLHelpers.ObjectGetFullName(node.ProcedureReference.Name));
|
||
public override void Visit(CreateOrAlterProcedureStatement node) => check(node, SQLHelpers.ObjectGetFullName(node.ProcedureReference.Name));
|
||
public override void Visit(AlterProcedureStatement node) => check(node, SQLHelpers.ObjectGetFullName(node.ProcedureReference.Name));
|
||
|
||
private void check(TSqlStatement node, string name)
|
||
{
|
||
var tokens = node.ScriptTokenStream;
|
||
|
||
bool hasDebugLog = false;
|
||
bool hasLabelFinish = false;
|
||
bool hasReturn = false;
|
||
|
||
List<ReturnPosition> returnPositions = new();
|
||
|
||
foreach (var token in tokens)
|
||
{
|
||
if (token.Text is null) continue;
|
||
|
||
if (token.Text.Equals("@DebugLog", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
hasDebugLog = true;
|
||
}
|
||
else if (token.Text.Equals("LABEL_FINISH:", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
hasLabelFinish = true;
|
||
}
|
||
else if (token.Text.Equals("RETURN", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
hasReturn = true;
|
||
returnPositions.Add(new(Line: token.Line, Column: token.Column));
|
||
}
|
||
}
|
||
|
||
if ((hasDebugLog || hasLabelFinish) || hasReturn)
|
||
{
|
||
returnPositions.ForEach(t => AddViolation(Name, Text, t.Line, t.Column, name));
|
||
}
|
||
}
|
||
|
||
private record ReturnPosition(int Line, int Column);
|
||
}
|