Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ The plugin is configured by editing the [configuration file](./TeamTools.TSQL.Li
Rules can be enabled or disabled, and their severity levels can be adjusted by setting the desired value next to the rule ID in the `rules` section of the config file:

| Value | Meaning |
|-------|---------|
| **off** | 🚫 Rule is disabled |
| **hint** | ℹ️ Rule violation is treated as an info message, suggestion, or recommendation |
| :-- | :-- |
| **off** | 🚫 Rule is disabled |
| **hint** | ℹ️ Rule violation is treated as an info message, suggestion, or recommendation |
| **warning** | ⚠️ Rule violation indicates a potentially significant warning, but not an explicit error |
| **error** | ⛔ Explicit compilation or runtime error |
| **error** | ⛔ Explicit compilation or runtime error |


However, avoid overstating the importance of certain rules by setting their severity to `error` for violations of conventions or optimization suggestions. This could unnecessarily fail CI pipelines. Instead, adjust the console utility’s overall **sensitivity level** (e.g., `--severity warning`). See the utility’s documentation for details.
Expand All @@ -68,6 +68,20 @@ Code parsing is performed by the [Microsoft/SqlScriptDOM](https://github.com/mic

Some rules may still work with other compatibility levels, but this has not been specifically tested.

## ⚠️ Known issues

| Rule Id | Issue | Description |
| :-- | :-- | :-- |
| **[CS0197](./TeamTools.TSQL.Linter/Resources/Docs/en-us/CS0197.md):CURSOR_COMMAND_ORDER** | False-positive | When cursor command is prepended with check of CURSOR_STATUS function then it’s fine no matter if command order looks like mistake. Rule implementation does not follow all code-flow branches and does not check IF-ELSE conditions. |
| **[CS0521](./TeamTools.TSQL.Linter/Resources/Docs/en-us/CS0521.md):SYSPROC_RETURN_NOT_CHECKED** | False-positive | If `sp_` or `xp_` proc which has no RETURN code is not mentioned in ignore list then it might be falsely reported by this rule. |
| **[CS0920](./TeamTools.TSQL.Linter/Resources/Docs/en-us/CS0920.md):UNPAIRED_TRAN_STATEMENT** | False-positive | False-positive detection: TRAN control may be fine because of IF-ELSE, TRY-CATCH logic. Rule implementation does not follow all code-flow branches and does not check IF-ELSE conditions. |
| **[CS0921](./TeamTools.TSQL.Linter/Resources/Docs/en-us/CS0921.md):UNPAIRED_XMLDOC_STATEMENT** | False-positive | False-positive detection: XML doc control may be fine because of IF-ELSE, TRY-CATCH logic. Rule implementation does not follow all code-flow branches and does not check IF-ELSE conditions. |
| **[PF0929](./TeamTools.TSQL.Linter/Resources/Docs/en-us/PF0929.md):NON_SARGABLE_PREDICATE** | False-positive | Complex predicates may contain a _primary_ filter which leads to fine execution plan alongside with _minor_ filter considered as non-sargable predicate which has no negative effect on query performance. |
| **[FA0904](./TeamTools.TSQL.Linter/Resources/Docs/en-us/FA0904.md):INDEX_REFERS_UNKNOWN_COL** | False-positive | If a table name is reused along the script with different structure then unnecessary "missing column" warnings are shown. |
| **[FA0949](./TeamTools.TSQL.Linter/Resources/Docs/en-us/FA0949.md):COLUMN_NOT_IN_GROUP_BY** | False-positive | If a similar in it's essence expression is written in different ways in SELECT and GROUP BY clauses it may be reporter as not grouped. |
| **[RD0236](./TeamTools.TSQL.Linter/Resources/Docs/en-us/RD0236.md):REDUNDANT_NEWLINE** | Low performance | Poor implementation leads to a substantial slowdown in the analysis process. |
| **[CD0215](./TeamTools.TSQL.Linter/Resources/Docs/en-us/CD0215.md):COMPUTED_COLS_ORDER** | Controversial | Regarding PERSISTED-colums the rule is right and not: such a column is anyways _computed_ ALTER, and at the same time is _stored_ thus moving the column towards column list tail means data reload. |

## Acknowledgments

Initially, the library was developed as a plugin for the [tsqllint](https://github.com/tsqllint/tsqllint) linter. Over time, its functionality outgrew that product’s capabilities, leading to its evolution into a standalone tool with its own runner and plugin protocol. Nevertheless, the team expresses deep gratitude to the authors of the mentioned project.
25 changes: 19 additions & 6 deletions README.ru-ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,18 @@

## Настройка

💡 _Для пробного запуска воспользуйтесь конфигом [EvaluateConfig.json](./TeamTools.TSQL.Linter/EvaluateConfig.json), в котором отключены большинство правил, касающихся соблюдения соглашний
💡 _Для пробного запуска воспользуйтесь конфигом [EvaluateConfig.json](./TeamTools.TSQL.Linter/EvaluateConfig.json), в котором отключены большинство правил, касающихся соблюдения соглашний
о форматировании, именовании и подобном. Укажите путь к этому конфигу в настройках консольного раннера либо просто подмените этим файлом DefaultConfig.json_

Плагин настраивается путем редайтирования [файла конфигурации](./TeamTools.TSQL.Linter/DefaultConfig.json). Таких конфигурационных файлов можно создать несколько, например, один для линтинга с учетом требований к именованию и форматированию, другой — только для поиска явных и потенциальных проблем. Правила можно отключить или включить обратно,
повысить или понизить серьёзность нарушения любого правила, установив нужное значение напротив идентификатора правила в разделе `rules` конфигурационного файла:

|||
|-|-|
| **off** | 🚫 правило отключено
| **hint** | ℹ️ нарушение правила учитывается как info-сообщение, подсказка, рекомендация
| Значение | Описание |
| :-- | :-- |
| **off** | 🚫 правило отключено
| **hint** | ℹ️ нарушение правила учитывается как info-сообщение, подсказка, рекомендация
| **warning** | ⚠️ нарушение правила означает потенциально значимое предупреждение, но не явную ошибку
| **error** | ⛔ явная ошибка времени компиляции или времени выполнения
| **error** | ⛔ явная ошибка времени компиляции или времени выполнения

Однако не стоит завышать значимость некоторых правил и превращать в ошибку (уровень значимости `error`) то, что является нарушением действующих соглашений
или предложением по оптимизации, чтобы таким образом переводить статус CI-пайплайна в состояние неуспеха. Вместо повышения severity конкретного правила
Expand All @@ -69,6 +69,19 @@

В других уровнях совместимости часть правил вполне может исправно работать, но это специально не тестировалось.

## ⚠️ Известные проблемы

| Идентификатор правила | Проблема | Описание |
| :-- | :-- | :-- |
| **[CS0197](./TeamTools.TSQL.Linter/Resources/Docs/ru-ru/CS0197.md):CURSOR_COMMAND_ORDER** | Ложное срабатывание | Если команде курсора предшествует проверка функции CURSOR_STATUS, то всё в порядке — независимо от того, выглядит ли порядок команд как ошибка. Реализация правила не отслеживает ветвление кода и не проверяет условия IF-ELSE. |
| **[CS0521](./TeamTools.TSQL.Linter/Resources/Docs/ru-ru/CS0521.md):SYSPROC_RETURN_NOT_CHECKED** | Ложное срабатывание | Если `sp_` or `xp_` хранимка фактически не возвращает статус через RETURN-код, но при этом не упомянута в списке игнорируемых, то на ней может быть ложное срабатывание. |
| **[CS0920](./TeamTools.TSQL.Linter/Resources/Docs/ru-ru/CS0920.md):UNPAIRED_TRAN_STATEMENT** | Ложное срабатывание | Ложное срабатывание: управление транзакциями может быть корректным из-за логики IF-ELSE, TRY-CATCH. Реализация правила не отслеживает ветвление кода и не проверяет условия IF-ELSE. |
| **[CS0921](./TeamTools.TSQL.Linter/Resources/Docs/ru-ru/CS0921.md):UNPAIRED_XMLDOC_STATEMENT** | Ложное срабатывание | Управление XML-документов может быть корректным из-за логики IF-ELSE, TRY-CATCH. Реализация правила не отслеживает ветвление кода и не проверяет условия IF-ELSE. |
| **[PF0929](./TeamTools.TSQL.Linter/Resources/Docs/ru-ru/PF0929.md):NON_SARGABLE_PREDICATE** | Ложное срабатывание | Сложные предикаты могут содержать _основной_ фильтр, который обеспечивает хороший план выполнения, наряду с _дополнительным_ фильтром, считающимся несаргабельным предикатом, который не оказывает негативного влияния на производительность запроса. |
| **[FA0904](./TeamTools.TSQL.Linter/Resources/Docs/ru-ru/FA0904.md):INDEX_REFERS_UNKNOWN_COL** | Ложное срабатывание | Если название таблицы переиспользуется в скрипте несколько раз с отличающимися структурами, то возможны излишние замечания про "несуществующую колонку". |
| **[FA0949](./TeamTools.TSQL.Linter/Resources/Docs/ru-ru/FA0949.md):COLUMN_NOT_IN_GROUP_BY** | Ложное срабатывание | Если одинаковое по сути выражение по-разному написано в SELECT и GROUP BY, то правило может на него среагировать. |
| **[RD0236](./TeamTools.TSQL.Linter/Resources/Docs/ru-ru/RD0236.md):REDUNDANT_NEWLINE** | Низкая производительность | Неудачная реализация приводит к существенному замедлению анализа. |
| **[CD0215](./TeamTools.TSQL.Linter/Resources/Docs/ru-ru/CD0215.md):COMPUTED_COLS_ORDER** | Спорное | В отношение PERSISTED-столбцов правило и право, и нет: такие столбцы всё же _вычисляемые_, поэтому к ним невозможно применять ALTER, но в то же время они _хранимые_, поэтому сдвиг такого столбца в конец таблицы означает перезаливку данных. |

## Благодарности

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ namespace TeamTools.TSQL.ExpressionEvaluator.BuiltInFunctions.DateFunctions
{
public class EndOfMonth : SqlGenericFunctionHandler<EndOfMonth.EndOfMonthArgs>
{
private static readonly int RequiredArgumentCount = 1;
private static readonly int MinArgumentCount = 1;
private static readonly int MaxArgumentCount = 2;

private static readonly string FuncName = "EOMONTH";
private static readonly string OutputType = TSqlDomainAttributes.Types.Date;

public EndOfMonth() : base(FuncName, RequiredArgumentCount)
public EndOfMonth() : base(FuncName, MinArgumentCount, MaxArgumentCount)
{
}

// TODO : respect optional second argument
public override bool ValidateArgumentValues(CallSignature<EndOfMonthArgs> call)
{
return ValidationScenario
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ protected override SqlValue DoEvaluateResultValue(CallSignature<DbIdArgs> call)
return new CurrentDatabaseId(value.TypeHandler, call.Context.NewSource);
}

if (call.ValidatedArgs.DatabaseName.IsNull)
if (call.ValidatedArgs.DatabaseName != null && call.ValidatedArgs.DatabaseName.IsNull)
{
call.Context.RedundantCall("DB name is NULL");

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using TeamTools.TSQL.ExpressionEvaluator.BuiltInFunctions.Abstractions;
using TeamTools.TSQL.ExpressionEvaluator.Routines;

namespace TeamTools.TSQL.ExpressionEvaluator.BuiltInFunctions.SysFunctions
{
public class MicrosoftVersion : GlobalVariableHandler
{
private static readonly string FuncName = "@@MICROSOFTVERSION";
private static readonly string ResultTypeName = TSqlDomainAttributes.Types.Int;

// TODO : Report on undocumented feature call?
public MicrosoftVersion() : base(FuncName, ResultTypeName)
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using TeamTools.TSQL.ExpressionEvaluator.BuiltInFunctions.Abstractions;
using TeamTools.TSQL.ExpressionEvaluator.Routines;

namespace TeamTools.TSQL.ExpressionEvaluator.BuiltInFunctions.SysFunctions
{
public class Version : GlobalVariableHandler
{
private static readonly string FuncName = "@@VERSION";
private static readonly string ResultTypeName = TSqlDomainAttributes.Types.NVarchar;

public Version() : base(FuncName, ResultTypeName)
{
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using NUnit.Framework;
using System.Collections.Generic;
using TeamTools.TSQL.ExpressionEvaluator.BuiltInFunctions.ArgumentDto;
using TeamTools.TSQL.ExpressionEvaluator.BuiltInFunctions.SysFunctions;
using TeamTools.TSQL.ExpressionEvaluator.TypeHandling;
using TeamTools.TSQL.ExpressionEvaluator.Values;
Expand Down Expand Up @@ -30,6 +32,17 @@ public void Test_DbId_ReturnsNullOnNullArgs()
Assert.That(res.IsNull, Is.True);
}

[Test]
public void Test_DbId_ReturnsApproximateValueIfInputIsNotStringLiteral()
{
var res = func.Evaluate(new List<SqlFunctionArgument> { new ValueArgument(null) }, Context);

Assert.That(res, Is.Not.Null);
Assert.That(res.IsNull, Is.False);
Assert.That(res.IsPreciseValue, Is.False);
Assert.That(res, Is.InstanceOf<SqlIntTypeValue>());
}

[Test]
public void Test_DbId_ReturnsApproximateValue()
{
Expand Down
Loading
Loading