AKML SQL — Static Code Analysis Rules

The analysis engine ships with 120+ rules across 8 categories. Rules run on every keystroke (debounced) and on save.

Rule Identifiers

Each rule has a unique ID of the form {Category}{Number}, e.g. PE001. Rules are configurable per-project via .casettings files and can be suppressed inline with -- akml-disable RuleId comments.

Severity Levels

Level Description
Error Definite bug or security issue — blocks or warns loudly
Warning Likely problem, should be reviewed
Information Style or best-practice guidance
Hint Subtle improvement, low priority
None Rule disabled

Severities can be overridden per-project in .casettings.


Performance (PE)

Rules that detect query patterns that harm runtime performance.

Rule Severity Auto-Fix Description
PE001 Warning SELECT * in stored procedures/views — returns unnecessary columns, prevents index-only scans
PE002 Warning Add dbo. Unqualified object names — causes plan cache pollution via recompilation
PE003 Error DELETE or UPDATE without a WHERE clause — affects all rows
PE004 Warning LIKE '%value' leading wildcard — forces full table scan, cannot use index
PE009 Warning Insert SET NOCOUNT ON Missing SET NOCOUNT ON in procedure — sends unnecessary row-count messages
PE010 Warning Replace with SELECT 1 SELECT * inside EXISTS(...) — wastes I/O, only existence matters
PE011 Warning ORDER BY inside INSERT INTO … SELECT — no effect and wastes sort cost
PE012 Warning SET options (ANSI_NULLS, QUOTED_IDENTIFIER, etc.) inside procedure body — should be outside
PE013 Warning Scalar function applied to a column in WHERE — makes the predicate non-SARGable
PE014 Information Missing index on foreign key column — FK lookups require table scans (schema required)
PE015 Warning IN list with more than 100 literal values — consider a temp table or TVP
PE016 Information Correlated subquery in WHERE — re-executes per outer row; consider a JOIN
PE017 Warning Non-SARGable function in WHERE (e.g. YEAR(col) = 2024) — use range predicate instead
PE018 Warning Table variable used for datasets that may exceed a few hundred rows — no statistics
PE019 Warning Table missing a clustered index — heap tables hurt range queries (schema required)
PE020 Information Index appears to be unused based on usage metadata (schema required)
PE021 Warning DISTINCT combined with GROUP BYDISTINCT is redundant after aggregation
PE022 Warning UNION without ALL — implicit DISTINCT adds a sort; use UNION ALL if duplicates are acceptable
PE023 Warning Subquery nesting depth exceeds 3 — consider CTEs for readability and potential plan improvements
PE024 Warning Unbounded SELECT without TOP/OFFSET-FETCH on large tables (schema required)
PE025 Warning GROUP BY clause with no aggregate functions — may indicate a DISTINCT was intended (schema required)
PE026 Information CROSS JOIN — produces a Cartesian product; ensure this is intentional
PE027 Warning SELECT INTO #temp inside a loop — repeated temp-table creation is expensive
PE028 Warning Cursor usage — prefer set-based operations where possible
PE029 Warning WHILE loop iterating over a table row-by-row — consider set-based alternative
PE030 Warning Repeated temp table usage — consider a Table-Valued Parameter for batching
PE031 Warning Implicit data-type cast in predicate — may prevent index use (schema required)
PE032 Warning Statistics may be stale based on modification counters (schema required)
PE033 Warning NOLOCK / READUNCOMMITTED hint — can return dirty reads and phantom rows
PE034 Information RECOMPILE hint — verify it is needed; excessive recompilation degrades throughput
PE035 Warning View without SCHEMABINDING — prevents indexed views and allows unnoticed breaking changes (schema required)

Best Practices (BP)

Rules that enforce correct, maintainable T-SQL patterns.

Rule Severity Auto-Fix Description
BP001 Warning @@IDENTITY used — returns identity from any scope; use SCOPE_IDENTITY() instead
BP002 Warning ISNUMERIC() used — returns true for values like $ and 1e2; use TRY_CONVERT
BP003 Warning No TRY/CATCH block in procedure with DML — unhandled errors leave transactions open
BP004 Error Replace with IS NULL = NULL comparison — always evaluates to UNKNOWN; use IS NULL
BP005 Warning EXEC(string) pattern — use sp_executesql with parameters to avoid SQL injection
BP006 Information Multiple DML statements without an explicit transaction — data may be partially committed
BP007 Warning Empty CATCH block — swallows errors silently
BP008 Information Add RETURN Missing RETURN at end of procedure — implicit RETURN 0 is not obvious
BP009 Warning Remove declaration Variable declared but never read
BP011 Information Insert SET XACT_ABORT ON SET XACT_ABORT ON missing in a procedure that uses transactions
BP012 Information Hard-coded date literal (e.g. '2024-01-01') — use a parameter or GETDATE()
BP013 Error Dynamic SQL built with string concatenation — use sp_executesql with parameters
BP014 Warning INSERT without an explicit column list — breaks if table schema changes
BP015 Information Add BEGIN/END Single-statement IF without BEGIN/END — fragile if a statement is added later
BP017 Warning GOTO usage — makes control flow hard to follow
BP018 Information IF nesting depth exceeds 3 — refactor into sub-procedures or CTEs
BP019 Hint Magic numeric constant — consider a named variable or configuration table
BP020 Warning OUTPUT parameter not assigned on all code paths
BP021 Information Procedure returns a single-row result set that could be OUTPUT parameters (schema required)
BP022 Hint PRINT statement — remove before production deployment
BP023 Warning OUTPUT parameter declared but never assigned (schema required)
BP024 Hint Parameter with no default value — callers must always supply it
BP025 Hint Procedure body exceeds 500 lines — consider splitting into sub-procedures
BP026 Information SELECT without FROM — use SELECT @var = value or a VALUES clause
BP027 Information UPDATE with a FROM JOIN — non-standard; behavior differs from ISO SQL
BP028 Information DELETE with a FROM JOIN — non-standard extension
BP029 Hint Scalar subquery in SELECT list — re-executes per row; consider a JOIN
BP030 Information Temp table referenced without schema qualifier — use #table consistently

Security (SE)

Rules that identify security vulnerabilities and misconfigurations.

Rule Severity Auto-Fix Description
SE001 Error EXEC() with concatenated string — SQL injection vector
SE002 Error Hard-coded password or credential literal in SQL text
SE003 Warning GRANT privilege to PUBLIC role — affects all users
SE004 Warning EXECUTE AS OWNER — elevates to object owner's permissions; verify intent
SE005 Warning TRUSTWORTHY ON for a database — allows CLR and ownership-chaining exploits
SE006 Warning Replace with HASHBYTES('SHA2_256',…) Weak hash algorithm (MD5 or SHA1) — not collision-resistant
SE007 Warning Cross-database object reference (OtherDb.dbo.Table) — increases attack surface
SE008 Error xp_cmdshell — executes OS commands; should be disabled in production
SE009 Warning OPENROWSET — accesses external data sources; can exfiltrate data
SE010 Warning Connection string containing credentials embedded in SQL
SE011 Warning sa login used directly — use dedicated least-privilege accounts
SE012 Warning Blank or empty password detected
SE013 Error Overly broad permission grant (e.g. CONTROL SERVER)
SE014 Warning DDL statement (CREATE/ALTER/DROP) inside a stored procedure body
SE015 Warning Object accessed without role-based permission check (schema required)
SE016 Warning Column name suggests sensitive data (SSN, credit card, etc.) without encryption
SE017 Warning Row-level security policy may be bypassed by the current user context (schema required)
SE018 Warning ENCRYPTBYPASSPHRASE — symmetric key encryption; prefer ENCRYPTBYKEY with AES-256
SE019 Warning Connection string literal found in procedure body
SE020 Warning Pattern suggests privilege escalation (e.g. adding a user to sysadmin)

Style (ST)

Rules that enforce consistent formatting and naming conventions.

Rule Severity Description
ST001 Information Inconsistent keyword casing — enforce UPPER, lower, or PascalCase
ST002 Information Old-style implicit alias (col alias without AS)
ST003 Information Old-style comma join syntax (FROM a, b WHERE a.id = b.id) instead of explicit JOIN
ST004 Information Missing statement terminator (;)
ST005 Information Inconsistent alias naming convention within the same query
ST006 Information Unnecessary square-bracket quoting on a non-reserved identifier
ST007 Information Object reference missing schema prefix (dbo.)
ST008 Information Inconsistent indentation detected
ST010 Information Line length exceeds configured maximum (default 120 characters)
ST011 Information Multiple SQL statements on a single line
ST012 Information Table alias defined inline without AS keyword
ST013 Information Missing blank line between top-level statements
ST014 Information Comment style inconsistency (-- vs /* */)
ST015 Information Data type keyword casing inconsistency
ST016 Information Built-in function reference missing schema prefix (e.g. dbo.fn_)
ST017 Information Column list items not aligned across clauses
ST018 Information TOP used without parentheses — TOP 10 vs TOP (10)
ST019 Information ORDER BY using ordinal position number instead of column name
ST020 Information SELECT DISTINCT where GROUP BY would be clearer
ST021 Information Mixed single and double quotes for string literals
ST022 Information Column alias uses camelCase — prefer PascalCase or consistent convention
ST023 Information Wildcard in object name pattern
ST024 Information Ambiguous date literal format (e.g. '01/02/03') — use ISO 8601 ('2024-01-02')
ST025 Hint Excessive comment density — more comments than code lines

Design (DE)

Rules that identify structural schema design problems (checked in DDL statements).

Rule Severity Description
DE001 Warning Table CREATE statement has no PRIMARY KEY constraint
DE002 Warning Table has no clustered index (schema required)
DE003 Error Nullable column included in a PRIMARY KEY constraint
DE004 Warning VARCHAR(1) or VARCHAR(2) — consider CHAR(n) for fixed-length values
DE005 Warning FLOAT or REAL used for monetary/financial data — use DECIMAL/MONEY
DE006 Warning SQL_VARIANT column — poor for indexing and type safety
DE007 Warning IDENTITY on a non-integer column type — unexpected behavior

Deprecated (DEP)

Rules that flag SQL Server features removed or discouraged in modern versions.

Rule Severity Auto-Fix Description
DEP001 Warning Replace with VARCHAR(MAX) / VARBINARY(MAX) text, ntext, or image data type — removed in SQL Server 2022+
DEP002 Warning Deprecated system stored procedure (e.g. sp_addtype, sp_bindrule)
DEP003 Warning SET FMTONLY ON — removed in SQL Server 2012
DEP004 Warning Old outer-join operators (*=, =*) — removed in SQL Server 2012
DEP005 Warning RAISERROR with style 0 and without NOWAIT — use THROW instead
DEP006 Warning Numbered procedure suffix (;1) — deprecated and ignored by the engine
DEP007 Warning GROUP BY ALL — removed in SQL Server 2012
DEP008 Warning Old-style locking hint without WITH (e.g. (NOLOCK) vs WITH (NOLOCK))

Execution (EX)

Rules that detect runtime errors detectable at parse/analysis time.

Rule Severity Description
EX001 Warning Division by literal zero (/ 0)
EX002 Warning Potential data truncation — inserting a longer value into a narrower column (schema required)
EX003 Error Ambiguous column reference — same column name exists in multiple joined tables (schema required)
EX004 Information Unreachable code after RETURN or THROW
EX005 Warning Identical condition in IF/CASE branches — one branch is dead code
EX006 Warning Always-true condition (1=1, 0=0) — likely a copy-paste artifact
EX007 Warning Unclosed cursor — a DECLARE CURSOR without a matching CLOSE + DEALLOCATE in the same batch
EX008 Warning Unbalanced transaction — BEGIN TRANSACTION count differs from COMMIT/ROLLBACK count (CATCH-block rollbacks excluded)

Naming (NM)

Rules that enforce naming conventions for database objects.

Rule Severity Auto-Fix Description
NM001 Warning Reserved word used as an identifier without quoting
NM002 Warning Rename to usp_ Procedure name starts with sp_ — SQL Server searches master first
NM003 Information Hungarian notation on table or view (tbl_, vw_)
NM004 Information Inconsistent naming style across objects of the same type
NM005 Warning Special characters in unquoted identifier
NM006 Information Single-letter table alias (a, b) — prefer descriptive aliases

Configuration

Per-Project Overrides (.casettings)

Place a .casettings file in any directory to override rule severities for that subtree:

{
  "rules": {
    "PE001": { "severity": "Error",   "enabled": true },
    "ST008": { "severity": "None",    "enabled": false },
    "NM002": { "severity": "Warning", "enabled": true }
  },
  "globalSuppressions": [
    { "ruleId": "NM003", "reason": "Legacy naming convention" }
  ]
}

Inline Suppressions

Suppress a rule for a block:

-- akml-disable PE001
SELECT * FROM dbo.Orders
-- akml-enable PE001

Suppress for a single line:

SELECT * FROM dbo.Orders  -- akml-disable-line PE001

Global Settings

See configuration.md for the codeAnalysis section of config.json:

Setting Default Description
enabled true Master switch
runOnType true Analyze after each keystroke (debounced)
runOnSave true Analyze on file save
autoFixOnFormat false Apply safe auto-fixes when running Format Document
squiggleStyle "underline" Squiggle rendering: underline, dotted, solid
showInErrorList true Show issues in the VS Error List window