SonarQube T-SQL Plugin provides native static analysis and AST-based linting for Microsoft Transact-SQL (T-SQL) in SonarQube and SonarCloud.
Powered by tsql-scriptdom-java, this plugin parses T-SQL files using Microsoft's official ScriptDOM grammar directly on the JVM—without external native CLI dependencies or .NET bridges.
- Language registration: Recognizes
.sqland.tsqlfiles as first-class Transact-SQL sources. - Deep AST analysis: Evaluates parsed Abstract Syntax Tree fragments with token streams and exact file coordinates.
- Cross-file DDL catalog: Builds a project schema catalog from
CREATE TABLE,CREATE INDEX, and related DDL in analyzed files. - Syntax error detection: Flags parsing and grammar violations with line and column precision.
- Built-in quality profile: The default
Sonar wayprofile activates the full built-in rule set out of the box. - Source Metrics: Publishes file measures for NCLOC, comment lines, and keyword-based complexity.
The sensor publishes the core file metrics SonarQube expects for T-SQL sources:
ncloc: non-comment lines of codecomment_lines: comment-only linescomplexity: complexity contributions from branching and exception-control constructs
Statement counts are not published. Semicolons and GO delimiters do not reliably count T-SQL statements; this measure requires a future implementation using the cached AST.
For complexity, the parser counts the primary T-SQL control-flow keywords that increase branching. In practice:
IFadds a branch point for each conditional blockWHILEadds loop complexity for iterative control flowCASEadds an alternate branch for each conditional expression or search expressionTRY/CATCHadds an exception flow path and structured error-handling branch
This means representative routines such as nested IF blocks, CASE expressions, looped WHILE statements, and TRY/CATCH blocks are reflected in the published complexity measure.
This repository currently registers 71 built-in T-SQL rules in the tsql repository and activates them in the default Sonar way profile (TSqlRulesDefinition + TSqlQualityProfile). The inventory below reflects the implementation at the current revision, not the initial five-rule baseline.
All implemented rules below are active by default in the built-in Sonar way quality profile. The default profile is created by TSqlQualityProfile.define(...) and marked as setDefault(true).
The keys below are the actual rule keys registered by TSqlRulesDefinition and activated in the default Sonar way profile. Custom plugin rules use their implementation names (for example AvoidSelectAll), while standard Sonar keys use the corresponding Sonar identifier (for example S1523, SR0014, S1614).
AvoidSelectAll, AvoidLeadingWildcardInLike, AvoidNoLockHint, AvoidDeprecatedTypes, S1590, S3641, S2527, S4054, S4094, S1523, S2070, S2068, S1614, S1745, S4078, S1735, S4801, S4102, S4149, SR0006, S4108, SR0009, SR0010, SR0011, S4413, S4196, SR0015, SR0016, S4819, S6498, S4154, S4155, S4103, S4104, S4109, S3643, S1742, SR0004, SR0007, SR0014, SyntaxError
S1481, S1172, S1065, S1763, S1751, S1656, S2737, S3626, S1764, S1862, S1871, S2761, S3633, S121, S131, S907, S1066
S103, S104, S105, S122, S125, S1134, S1135, NoSonar, S1451, S3972, S3973, S138, S1151
The
Sonar wayprofile is the default profile; it is not a partial or experimental subset. The plugin intentionally ships the complete rule set that is implemented in code and metadata.
The plugin builds a project-wide schema catalog from the T-SQL DDL it can parse in the analyzed codebase. This catalog is used by schema-aware checks such as:
SR0004(InPredicateIndexedColumn)SR0007(NullableColumnIsNull): detects ASCII literal replacements longer than a known bounded nullable character column inISNULL. Nullability comes from parser constraints or explicit column declarations in analyzed source files; omitted/unknown nullability is skipped. ValidCOALESCEexpressions are compliant.SR0014(NarrowingCast)
S1614 (PrimaryKeyRequired) inspects CREATE TABLE statements directly and does not depend on the cross-file project catalog.
CREATE TABLEstatements, including column definitions and basic nullability metadataCREATE INDEX/ indexed column discovery for the project scope- Cross-file resolution of table and column names within the analyzed project for those checks that explicitly read the project catalog
- Case-insensitive table / column matching for SQL Server-style identifier behavior
- Live database metadata or remote schema introspection
- Dynamic DDL generation, runtime schema creation, or migration tools executed outside the analyzed files
- Full dependency analysis across external libraries, generated scripts, or stored procedures not included in the project scan
- Full SQL Server semantic coverage such as alias resolution beyond the simplest same-name lookups, advanced partitioning, constraint semantics, or runtime object metadata
This catalog is intentionally best-effort: it is designed to support project-aware checks without requiring a remote database connection or a full SQL Server engine. Table identity preserves database/schema qualifiers, and query scopes resolve FROM aliases against the cached AST for each file. Unqualified columns with multiple known sources remain unresolved. Scope bindings survive catalog construction across files and do not use file-local token offsets to infer another file's scope. The pinned parser can omit JOIN operands, so complete JOIN analysis is not yet reliable; see issue #61.
The implemented rules are intentionally scoped to what the plugin can reason about reliably from the parsed T-SQL AST and the in-repo schema catalog.
- AST-only logic: Many checks are syntax-aware but not full semantic execution analysis.
- Schema limitations: Cross-file DDL metadata is derived from project files only and is not a live database schema.
- No runtime metrics: The plugin does not infer live query plans, execution timing, or distribution metrics from a running SQL Server instance.
- No deep duplicate analysis: The project does not currently implement repository-wide duplicate-code analysis or structural deduplication reporting.
- No highlighting layer: Inline editor highlights, code lens annotations, and richer UX-only rendering are not part of the current plugin behavior.
Implemented today:
- AST parsing and rule execution for T-SQL files
- Built-in Sonar rule registration and the default
Sonar wayquality profile - Schema-aware checks that rely on the best-effort project DDL catalog
- Rule metadata, severities, tags, and repository registration
Not currently implemented:
- Syntax highlighting in the IDE or Sonar UI
- CPD token-based duplication detection
- Live SQL execution metrics, runtime query plans, or dashboards backed by a running SQL Server instance
- SonarQube Server: 9.9.1-community (minimum supported release) and 25.1.0.102122-community (current supported server version exercised by the packaged-plugin smoke test)
- Java Runtime: Java 17 or higher
- SQL Server Versions: SQL Server 2008 through SQL Server 2022, Azure SQL Database
The packaged plugin is smoke-tested against the minimum supported SonarQube release and the current API target using the harness in scripts/sonarqube-smoke-test.sh.
This repository is currently on the 0.1.0-SNAPSHOT development line and does not have a published production release on GitHub Releases yet. Until a release tag is created and published, install the plugin by building the current checkout from source.
Prerequisites for source builds:
- Java Development Kit (JDK) 17+
- Maven 3.8+
- Build the current project from source:
git clone https://github.com/fupacat/sonar-tsql-plugin.git cd sonar-tsql-plugin mvn clean package - Copy the generated JAR into your SonarQube server's plugin directory:
cp target/sonar-tsql-plugin-*.jar $SONARQUBE_HOME/extensions/plugins/
- Restart your SonarQube server:
$SONARQUBE_HOME/bin/linux-x86-64/sonar.sh restart - Verify under Administration > Marketplace > Installed Plugins that "SonarQube T-SQL Plugin" is active.
For a tagged release such as v0.1.0, the plugin artifact will be named target/sonar-tsql-plugin-0.1.0.jar, matching the Git tag without the leading v.
Release publication is triggered by pushing a matching semantic-version tag (vX.Y.Z). The workflow enforces that the requested tag exists, the POM version matches the tag, and the packaged artifact exists with the expected plugin class before creating the GitHub release.
Before tagging:
- Update
pom.xmlto the intended release version (for example0.1.0) and remove-SNAPSHOT. - Update
CHANGELOG.mdto the same version and record the release notes. - Run
mvn clean verify --batch-modelocally to confirm the release artifact builds cleanly.
Publish:
- Create and push the matching Git tag, such as
v0.1.0. - Confirm the
Releaseworkflow succeeds for that tag.
The consistency test in TSqlRulesDefinitionTest extracts every documented rule key from the category lists and compares the complete set against the registered RulesDefinition repository, rejecting missing, extra, or duplicate entries. It also checks the displayed rule count against the registry size and verifies the default profile and catalog documentation. This keeps the inventory aligned with the actual Sonar rule keys rather than implementation class names.
The smoke test requires JDK 17+, Maven 3.8+, and Docker.
mvn -DskipTests package
SQ_VERSION=9.9.1-community ./scripts/sonarqube-smoke-test.sh
SQ_VERSION=25.1.0.102122-community ./scripts/sonarqube-smoke-test.shThe smoke test starts a SonarQube container, installs the built JAR, scans the fixture project under integration/smoke/fixture, and validates that:
- the
tsqllanguage is registered; - the built-in rules and
Sonar wayprofile are active; - the fixture produces issues under the plugin; and
- cross-file schema/routine scan behavior works for separate DDL and routine files.
This project is licensed under the MIT License. T-SQL parsing capabilities powered by tsql-scriptdom-java.