T-SQL Conformance
Lanexio™ Parser implements T-SQL (Microsoft SQL Server) as a lexer-level dialect
of the SQL grammar (ADR 0035 curated intersection), completed in ADR 0045. There
is deliberately no separate parser-grammar-tsql package: a standalone pack
would duplicate the SQL lexer and contradict the ADR 0035 decision.
The T-SQL surface covered by this conformance gate includes:
#-identifiers (temporary-table#name/##name, plus#/##followed by$/@), bracket[identifiers], and@-variable parameters.DECLARE @var [TYPE],SET @var =,BEGIN...ENDandTRY...CATCHblocks, CREATE PROCEDURE/FUNCTION/VIEW bodies,EXEC/EXECUTE,OUTPUT,MERGE,GObatch separators, and sqlcmd client directives.- Money literals (
$1,$.01) and the!</!>/! =and^operators.
Statement-level structural validation is tsql-gated, so the ANSI / postgres / mysql / sqlite corpus behavior is unchanged.
Leniency: statement heads
Section titled “Leniency: statement heads”The statement-head typo hardening (which flags SELCT * FROM t under
ansi/postgres) is disabled for the tsql dialect. A bare identifier at
statement-head is a valid implicit EXEC (a stored-procedure name as the first
statement in a batch runs without EXEC), and dialect verbs outside the shared
head set (RECONFIGURE, GOTO, SHUTDOWN, RENAME TABLE, DISABLE/ENABLE TRIGGER,
SEND, GET CONVERSATION) begin real statements. SELCT * FROM t therefore parses
clean under tsql while ansi/postgres flag it. This is ADR 0041 decision 4
over-acceptance: structural defects are still caught by the statement-linter
rules at ;/EOF.
Dialect selection
Section titled “Dialect selection”parseSql(bytes, { dialect: "tsql" }) selects the T-SQL surface directly:
import { parseSql } from '@lanexio/parser-grammar-sql';
const tree = parseSql(encoder.encode('CREATE TABLE #tmp (id int,);'), { dialect: 'tsql' });console.log(tree.root.hasError); // falseThe unified parse() accepts the tsql, mssql, and sqlserver spellings and
routes them to the SQL grammar with the tsql dialect forced (ADR 0045):
import { parse } from '@lanexio/parser';
const tree = parse('DECLARE @x int; SET @x = 1;', { language: 'tsql' });console.log(tree.metadata.language); // "sql"console.log(tree.metadata.dialect); // "tsql"Harness and gates
Section titled “Harness and gates”pnpm tsql:conformance runs scripts/tsql-conformance.mjs over the 468-file
test_files/tsql corpus (155 manifest-ledgered cases plus 313 root-level
reference files):
| Gate | Assertion |
|---|---|
manifest accept | root clean (no SqlKind.Error) |
manifest reject / reject-core | root flagged |
manifest recover | flagged but a later statement node is produced |
manifest accept-client | recorded but excluded (SQLCMD client preprocessing is not implemented) |
| root-level files | root clean + never-throw + lossless (flat AST leaf partition) |
| manifest conform % | >= 95 over the classified cases (denominator 155 - 3 accept-client = 152) |
| root-level clean % | 100% |
Two ledger expectations are documented over-acceptance: the reject-core GO and
sqlcmd cases (270_go_is_not_tsql.sql, 271_sqlcmd_is_not_tsql.sql) are
leniently accepted because GO batch separators and sqlcmd directives are client
preprocessing, not core statement grammar (ADR 0041 decision 4). They are the
bounded toleration that keeps the aggregate at 150/152 = 98.7% while the
remaining 150 classified cases are exact.
The same manifest and root-file assertions run against the source in the package
test suite (tsql-conformance.test.ts), so the gate is enforced in CI both on
the built dist (harness script) and under test (vitest).
Current numbers
Section titled “Current numbers”Measured on this tree with pnpm tsql:conformance:
- Manifest: 150/152 classified conform = 98.7% (>= 95 gate; only the two documented GO/sqlcmd over-acceptance cases fail).
- Root-level files: 313/313 clean.
Trailing-comma leniency
Section titled “Trailing-comma leniency”A trailing comma before the closing paren of a T-SQL CREATE TABLE column list
is valid and parses clean, regardless of the table-name shape: a bare name
(CREATE TABLE t (a int,)), a schema-qualified name (CREATE TABLE dbo.t (id int,)), a bracket-delimited name (CREATE TABLE [t] (a int,)), and a
temporary-table name (CREATE TABLE #t (a int,)) all parse clean. An empty
column list (CREATE TABLE t ()) is rejected, because T-SQL requires at least
one column definition. The leniency does not extend to table variables, function
argument lists, INSERT column lists, or ORDER BY: a function-argument trailing
comma such as SELECT COALESCE(a, b,) is still flagged.
Related
Section titled “Related”- SQL conformance
- Parsing SQL guide
- ADR 0045: SQL conformance >95% and T-SQL dialect completion (recorded in
docs/decisions/0045-sql-tsql-conformance.md)