A pure Java port of Microsoft's ScriptDOM (Microsoft.SqlServer.TransactSql.ScriptDom), the canonical Transact-SQL (T-SQL) parser and Abstract Syntax Tree (AST) engine powering SQL Server Data Tools (SSDT), Azure Data Studio, and SQL Server Management Studio (SSMS).
Built to provide deterministic, linear-time
- The SonarQube Gap: SonarQubeβs official T-SQL analyzer is closed-source and gated behind the paid commercial Developer Edition ($$$). SonarQube Community Edition has no native T-SQL analyzer.
-
The ANTLR 4 Pitfall: Community ANTLR 4 T-SQL grammars (
antlr/grammars-v4) suffer from catastrophic backtracking and memory bloat under ANTLR 4's dynamic$ALL(*)$ algorithm when parsing complex, ambiguous T-SQL statements. Furthermore, generic parse trees require thousands of lines of fragile manual glue before inspection rules can run. -
Canonical Microsoft Engine: Microsoft open-sourced microsoft/SqlScriptDOM under the MIT License. It features:
- A hand-tuned, deterministic
$LL(2)$ lookahead parser (via ANTLR 2.7.5). - A declarative XML schema (
Ast.xml) defining ~500+ strongly-typed AST nodes (SelectStatement,TableReference, etc.). - A complete visitor pattern hierarchy (
TSqlFragmentVisitor). - Over 1,100 production test cases directly from Microsoft SQL Server engineering.
- A hand-tuned, deterministic
The project is structured as a multi-module Maven build targeting Java 17+:
tsql-scriptdom-java/
βββ pom.xml <-- Parent POM
βββ tsql-scriptdom-astgen/ <-- Code generator parsing Ast.xml -> Java AST & Visitors
β βββ src/main/java/ <-- Java AST generator implementation (using JavaPoet)
β βββ src/main/resources/ <-- Ast.xml (upstream schema)
βββ tsql-scriptdom-core/ <-- Runtime parser & AST library
βββ src/main/java/ <-- Parser facade, base token filters, runtime helpers
βββ src/main/resources/
βββ grammar/ <-- TSql160.g (ANTLR v2) & TSqlTokenTypes.g
βββ schema/ <-- Ast.xml
- Scope Reduction: Upstream ScriptDOM contains 750 files dedicated to
ScriptGenerator(formatting ASTs back into SQL text). Because static analysis and linters only inspect ASTs and never regenerate T-SQL scripts,ScriptGeneratoris omitted. This reduces porting complexity by over 50%. - Superset Parser Architecture (
TSql180): The parser engine is powered by Microsoft's latestTSql180grammar (SQL Server 2025 / Azure SQL bleeding-edge), including Vector search, vector indexes, DiskANN, JSON enhancements, and windowing. - Compatibility Validation (
SqlCompatibilityValidator): Rather than bundling 12 separate ANTLR grammars (~1,000,000 lines of generated code and 25MB of JAR bloat), the library uses a single high-performance superset parser combined with an AST visitorSqlCompatibilityValidatorthat checks compatibility against any targetSqlVersion(SQL Server 2000 / 80 through SQL Server 2025 / 180). - Standard ANTLR 2 Runtime: Powered by
antlr:antlr:2.7.7, ensuring 100% pure Java execution with zero native binary or platform dependencies.
Add the dependency to your project:
<dependency>
<groupId>io.github.fupacat</groupId>
<artifactId>tsql-scriptdom-core</artifactId>
<version>0.1.1</version>
</dependency>implementation 'io.github.fupacat:tsql-scriptdom-core:0.1.1'Note:
tsql-scriptdom-corehas zero external transitive dependencies. The ANTLR runtime is completely shaded and relocated internally (io.github.fupacat.internal.antlr) to eliminate classpath collisions.
import io.github.fupacat.ParseResult;
import io.github.fupacat.TSqlParser;
import io.github.fupacat.ast.TSqlScript;
String sql = "SELECT u.id, u.username FROM dbo.Users AS u WHERE u.isActive = 1;";
ParseResult<TSqlScript> result = TSqlParser.parse(sql);
if (result.isSuccess()) {
TSqlScript script = result.fragment();
System.out.println("Parsed script batches: " + script.Batches.size());
} else {
result.errors().forEach(err ->
System.err.println("Line " + err.line + ", Col " + err.column + ": " + err.message)
);
}import io.github.fupacat.ast.SelectStatement;
import io.github.fupacat.ast.TSqlConcreteFragmentVisitor;
result.fragment().accept(new TSqlConcreteFragmentVisitor() {
@Override
public void visit(SelectStatement selectStatement) {
System.out.println("Discovered SELECT query: " + selectStatement);
}
});import io.github.fupacat.SqlVersion;
// Check if modern SQL 2022/2025 syntax is valid on a legacy SQL Server 2016 target
ParseResult<TSqlScript> legacyCheck = TSqlParser.parse(
"SELECT c1, SUM(c2) OVER w FROM dbo.t WINDOW w AS (PARTITION BY c1);",
SqlVersion.SQL130 // SQL Server 2016
);
if (legacyCheck.hasErrors()) {
legacyCheck.errors().forEach(e -> System.out.println("Incompatible: " + e.message));
}The packaged JAR can be executed directly as a standalone CLI to validate T-SQL queries or files:
# Validate inline T-SQL
java -jar tsql-scriptdom-core-0.1.0-SNAPSHOT.jar "SELECT 1 FROM dbo.t;"
# Validate a SQL script file
java -jar tsql-scriptdom-core-0.1.0-SNAPSHOT.jar -f /path/to/script.sql- Phase 0: Project scoping, upstream architectural audit, and repo initialization.
- Phase 1: AST Code Generation (
tsql-scriptdom-astgen)- Port
AstGento Java using JavaPoet. - Generate ~500 strongly-typed AST classes from
Ast.xml. - Generate
TSqlFragmentVisitorandTSqlConcreteFragmentVisitor.
- Port
- Phase 2: Base Parser Runtime & Lexer
- Port
TSqlTokenFilter(comment and whitespace handling). - Port
TSqlLexerBaseInternalandTSql160ParserBaseInternal(predicate helpers and validation tables).
- Port
- Phase 3: Grammar Translation & Superset Parser (
TSql180.g)- Adapt C# semantic actions to Java in
TSql180.gandTSqlTokenTypes.g. - Compile superset parser via ANTLR 2.7.7.
- Implement public facade
TSql180Parserand backwards-compatibleTSql160Parser. - Implement
SqlVersionenum (SQL80toSQL180) andSqlCompatibilityValidator.
- Adapt C# semantic actions to Java in
- Phase 4: Upstream Regression Verification
- Ingest upstream test scripts from Microsoft's test suite into parameterized JUnit 5 tests (458 scripts verified, 100.0% pass rate: 454 positive ASTs + 4 verified negative/deprecated syntax rejection tests, 90/90 JUnit tests passing).
- Phase 5: Standalone Packaging, CI/CD, & Distribution
- Package shaded standalone CLI (
tsql-scriptdom-core) with zero external runtime dependencies. - High-level facade (
TSqlParser,ParseResult) and AST visitor traversal API. - CI/CD multi-JDK test matrix (Java 17 & 21), automated release workflow, and GitHub Packages / Maven Central distribution.
- Package shaded standalone CLI (
- Phase 6: SonarQube Language Plugin (
sonar-tsql-plugin)- Standalone companion repository consuming
tsql-scriptdom-core. - Syntax highlighting, CPD duplication, code metrics, and AST-based quality & security rules.
- Standalone companion repository consuming
tsql-scriptdom-java provides full coverage of the standard Transact-SQL engine powering:
- Box SQL Server: SQL Server 2000 (
SQL80) through SQL Server 2025 (SQL180). - Azure SQL: Azure SQL Database, Azure SQL Managed Instance.
- Modern Features: Vector search / distance metrics, vector indexes, DiskANN, JSON enhancements (
JSON_OBJECT,JSON_ARRAY,JSON_OBJECTAGG,JSON_ARRAYAGG,RETURNING JSON), modern windowing, and graph tables.
Specialized cloud data warehouse engines implement divergent syntax not present in the standard SQL Server database engine:
- Microsoft Fabric Data Warehouse (
EngineType.FabricDW): Fabric-specific statements such asCLUSTER BY, Fabric AI functions (AI_GENERATE_RESPONSE,AI_SUMMARIZE), andALTER EXTERNAL FUNCTION. - Azure Synapse / Azure SQL Data Warehouse (
EngineType.SqlDw): MPP distribution syntax such asDISTRIBUTION = HASH(...)/ROUND_ROBINinCREATE MATERIALIZED VIEW, Azure DWCOPY INTO, and workload classification for MPP.
These warehouse scripts are omitted from the core engine test suite because they require warehouse-specific ANTLR grammar variants.
Transact-SQL has intentionally removed obsolete constructs across major versions:
DISK INIT(SQL Server 6.5 / 7.0 disk device management, removed in SQL Server 2005).DUMP DATABASEandLOAD DATABASE(Sybase heritage commands, removed in SQL Server 2005/2008).FASTFIRSTROWtable hint (deprecated in SQL Server 2005/2008, removed in SQL Server 2012 /TSql110).
In upstream Microsoft SqlScriptDOM, scripts testing these removed constructs (MiscTests80.sql, DumpLoadStatement90Tests.sql, MiscDeprecatedIn110Tests.sql) are marked as negative tests when evaluated against modern parsers (TSql110 through TSql180). Our regression suite validates them as negative tests to guarantee that obsolete syntax is properly flagged and rejected by the modern TSql180 grammar.
This project is licensed under the MIT License.
tsql-scriptdom-java is derived from Microsoft's open-source SqlScriptDOM, Copyright Β© Microsoft Corporation, licensed under the MIT License. See NOTICE.md for full attribution.