AKML SQL — Formatter Reference Updated
Overview
The SQL formatter rewrites T-SQL text according to a formatting profile (.akmlstyle), preserving semantic equivalence. It runs as part of the out-of-process Engine and is invoked via the IPC API.
Formatting Pipeline
The pipeline processes SQL in sequential stages. Failures in the semantic validation stage cause the original SQL to be returned unchanged.
Input SQL
Stage 0a: NoformatScanner → identifies -- noformat / -- endnoformat regions
Stage 0b: SqlcmdPreprocessor → replaces :r / :setvar directives with placeholders
Stage 1: TSql170Parser → parses into TSqlScript AST
Stage 2: AstAnnotator → attaches comments to AST nodes
Stage 3: LayoutEngine → produces LayoutNode list (tokens + whitespace rules)
— or, for a style written in SQL Prompt's model, SqlPromptLayout (see below)
Stage 4: CasingEngine → applies keyword/identifier casing from profile
Stage 5: TextEmitter → emits formatted string
Stage 5b: SqlcmdPreprocessor → restores SQLCMD placeholders
Stage 6: SemanticValidator → re-parses both versions; normalizes and compares
Stage 7: IdempotencyCheck → formats again; verifies output is identical
Output FormattedSQL
Stage details
| Stage | Class | Notes |
|---|---|---|
| 0a | NoformatScanner |
Scans for -- noformat / -- endnoformat markers; protected regions pass through unchanged |
| 0b | SqlcmdPreprocessor |
Replaces :r file and :setvar with unique placeholders to prevent parse errors |
| 1 | TSql170Parser |
Microsoft TSqlParser with initialQuotedIdentifiers: true |
| 2 | AstAnnotator |
Walks the AST and attaches preceding/trailing comment tokens to nodes |
| 3 | LayoutEngine |
Converts AST + profile options into an IR list of LayoutNode items |
| 4 | CasingEngine |
Applies CasingOptions to keyword and identifier tokens |
| 5 | TextEmitter |
Serializes the IR into a string |
| 5b | SqlcmdPreprocessor |
Restores original SQLCMD text |
| 6 | SemanticValidator |
Parses the formatted output and the original AST, normalizes both, and compares token streams |
| 7 | IdempotencyCheck |
Formats the output a second time; if the result differs, emits a diagnostic warning |
Stage 6 failure: returns original SQL unchanged. Stage 7 failure: returns the (possibly non-idempotent) formatted SQL with a diagnostic warning appended.
SQL Prompt Styles (spec 039)
A style can be written in SQL Prompt's own model: the .akmlstyle then carries a
"sqlPrompt" object — exactly the JSON document SQL Prompt 10.5+ reads and writes (one file per
style: metadata, whitespace, lists, parentheses, casing, dml, ddl, controlFlow,
cte, variables, joinStatements, insertStatements, functionCalls, caseExpressions,
operators). Such a style is its document: it formats from it, the style editors edit it,
and import / export move it unchanged.
{
"metadata": { "name": "Team", "id": "…" }, // AKML metadata
"sqlPrompt": { // the style (SQL Prompt's JSON)
"metadata": { "id": "…", "name": "Team" },
"lists": { "placeCommasBeforeItems": true },
"casing": { "reservedKeywords": "uppercase" }
},
"list": { "commaPosition": "leading" }, … // projection for older builds
}
Layout. FormatterPipeline.Layout sends a style with a document to the SQL Prompt layout
(src/AkmlSql.Formatting/SqlPrompt/) and every other style to the rule-based layout below
(unchanged). Parsing, casing, formatting-off regions, semantic validation and the idempotency
check are shared. The SQL Prompt layout emits every token once, in order, deciding only the
whitespace before each (Layout/SqlWriter), so no option can change what the SQL means; one
printer per construct (Layout/SqlPromptPrinter.*) reads its options straight from the style.
Options. SqlPromptOptionCatalog holds SQL Prompt's 114 schema options plus
whitespace.newLines.alignMultilineCommentsMatchingPatterns, grouped as SQL Prompt's editor
groups them (Global: Whitespace, Lists, Parentheses, Casing · Statements: Data (DML), Schema
(DDL), Control flow, CTE, Variables · Clauses: Join, Insert · Expressions: Function calls, CASE,
Operators), with labels, allowed values, defaults, which option turns another on, and notes. It is
pinned to Redgate's vendored schema by test. How each ambiguous option is read, and where to
correct it, is listed in specs/039-sqlprompt-style-editor/spec.md.
The document. SqlPromptStyleDocument keeps SQL Prompt's minimal form (an option at its
default is left out), reads keys and values case-insensitively, keeps keys this build does not
know, reads Redgate's historical intentedFromWhen typo, and applies SQL Prompt 11's collapse
rule: a …ShorterThan threshold written without its collapseShort… switch means the collapse is
on; switching it off writes false explicitly.
Styles written in AKML's model keep formatting exactly as before. The editors show their SQL
Prompt reading (SqlPromptProjection, or the .source.json a spec-031 import kept); saving one
from an editor makes it a SQL Prompt style.
Editors.
- Web edition: Format styles page (
/styles). Styles are saved to the paired engine when it advertisesstyles.sqlprompt.v1— the styles folder SSMS uses — otherwise in the browser (IndexedDB). Built-ins are edited as copies that shadow them (Reset restores). - SSMS: the Format Styles window asks the engine for SQL Prompt's model
(
StyleEditorSchemaRequest.SqlPromptModel); settings aresqlPrompt.<path>, so preview and save carry the document. Against an older engine the window falls back to AKML's settings schema. - Both preview each page's own sample (
SqlPromptPreviewSamples) or the user's SQL, and reformat on every change.
Import / export. Importing a SQL Prompt .json keeps its document and id. Exporting to a path
ending in .json writes the style's SQL Prompt document in SQL Prompt's minimal form (UTF-8, no
BOM); .sqlpromptstylev2 export (SQL Prompt 9 XML) is unchanged.
PostgreSQL (spec 042)
A script of a PostgreSQL connection is formatted by its own formatter (AkmlSql.PostgreSql/Formatting, run by the engine; the web edition asks the
engine). The style is any style: one written in SQL Prompt's model is used as it is, one in AKML's own model is read as its SQL Prompt equivalent
(SqlPromptStyles.ToDocument).
- Layout. Tokens in, tokens out: every token of the script is printed once, in order; the layout decides only the white space and the case of
keywords, functions and data types. Names are never recased, quotes are never added or removed, string constants and dollar-quoted bodies
(functions,
DOblocks) are verbatim. Clause alignment, lists, parentheses, CTEs, joins,CASE,AND/OR,BETWEEN,IN,INSERT, function calls and the layout ofCREATE TABLE/INDEX/VIEWfollow the style's options;MERGE,EXPLAIN,PREPAREand the other statements keep their own line breaks (a long one-line statement wraps after its top-level commas). - Safety. The script must parse (otherwise it is returned unchanged with the first error). The result must parse to the same statements (location-free tree comparison), hold the same tokens and comments in the same order, and format to itself. Any failure returns the original with a message.
- Options with no PostgreSQL meaning (control flow, variables, batch separators, global variables, comparison alignment ...) are listed in
SqlPromptApplicabilityand marked "No effect for PostgreSQL" in the Format Styles page while a PostgreSQL connection is active, whose preview is a PostgreSQL sample. The formatter never reads them. - Format SQL actions. Case only; add / remove the last terminator; expand wildcards and qualify names with PostgreSQL quoting (both need the
schema). Square brackets,
ASkeyword and the T-SQL rewrites are not available. - Parse (Ctrl+F5) checks the syntax with the PostgreSQL parser, without the server, and lists every error with its line and column.
- Corpus.
tests/pg-format-corpus: 151 scripts x the 8 built-in styles, every pair parse-equivalent, stable, literal-preserving and equal to its golden (AKML_UPDATE_PG_GOLDENS=1regenerates).
noformat Regions
Wrap any block you want the formatter to skip:
-- noformat SELECT weird spacing FROM dbo.LegacyTable -- endnoformat
The NoformatScanner identifies these regions before parsing, so even syntactically unusual SQL is safe.
Profile Files (.akmlstyle)
Profiles are stored as JSON files:
%AppData%\AKML SQL\profiles\{name}.akmlstyle
Built-in profiles (read-only) are embedded in the extension. User profiles can be created, edited, imported, and exported via the Options UI.
Profile file structure
{
"metadata": {
"id": "d3b07384-d9a4-4b8b-9a1d-3b4f5c6d7e8f",
"schemaVersion": 1,
"name": "My Profile",
"description": "Adapted from Default",
"author": "Jane Dev",
"version": "1.0.0",
"created": "2024-06-01T12:00:00Z",
"modified": "2024-07-15T09:30:00Z",
"basedOn": null,
"isBuiltIn": false,
"skipValidation": false,
"enableIdempotencyCheck": true
},
"whitespace": { ... },
"casing": { ... },
"list": { ... },
"parenthesis": { ... },
"dml": { ... },
"join": { ... },
"ddl": { ... },
"controlFlow": { ... },
"case": { ... },
"cte": { ... },
"expression": { ... },
"actions": { ... }
}
Profile Options Reference
metadata
| Key | Type | Default | Description |
|---|---|---|---|
id |
string (UUID) | auto | Unique profile identifier |
schemaVersion |
int | 1 | Profile schema version (for future migrations) |
name |
string | — | Display name |
description |
string | — | Optional description |
author |
string | — | Creator name |
version |
string | "1.0.0" |
SemVer string |
created |
string | ISO 8601 | Creation timestamp |
modified |
string | ISO 8601 | Last modified timestamp |
basedOn |
string? | null |
UUID of parent profile |
isBuiltIn |
bool | false |
Read-only built-in profile flag |
skipValidation |
bool | false |
Skip semantic round-trip (for test pipelines) |
enableIdempotencyCheck |
bool | true |
Enable second-pass idempotency verification |
whitespace
Controls line breaks, indentation, and spacing.
| Key | Type | Default | Description |
|---|---|---|---|
tabStyle |
"spaces" | "tabs" |
"spaces" |
Indentation character |
tabSize |
int | 4 | Spaces per indent level |
indentStyle |
"block" | "hanging" |
"block" |
Block vs hanging indent for continuations |
maxLineWidth |
int | 120 | Soft line-length limit |
lineBreakBeforeClause |
bool | true | New line before SELECT, FROM, WHERE, etc. |
lineBreakAfterClause |
bool | false | New line after clause keyword |
lineBreakBeforeComma |
bool | false | Leading comma style (,col vs col,) |
lineBreakAfterComma |
bool | true | Trailing comma — break after each comma |
emptyLineBetweenStatements |
int | 1 | Blank lines inserted between top-level statements |
emptyLineBeforeGO |
bool | true | Blank line before GO batch separator |
emptyLineAfterGO |
bool | true | Blank line after GO |
preserveEmptyLinesAfterBatch |
bool | false | Keep the author's existing blank line (or none) after GO, skipping the emptyLineAfterGO normalisation |
preserveEmptyLines |
bool | true | Keep existing blank lines (up to maxConsecutiveEmptyLines) |
maxConsecutiveEmptyLines |
int | 2 | Cap on consecutive blank lines |
trailingWhitespace |
"remove" | "preserve" |
"remove" |
Trailing spaces on each line |
finalNewline |
"ensure" | "remove" |
"ensure" |
Ensure file ends with a newline |
spaceAfterComma |
bool | true | Space after , in lists |
spaceAroundOperators |
bool | true | Spaces around =, +, >, etc. |
spaceAroundBooleanOperators |
bool | true | Spaces around AND, OR, NOT |
spaceInsideParentheses |
bool | false | Spaces inside ( expr ) |
spaceBeforeParentheses |
bool | false | Space before ( in function calls |
lineBreakAfterSemicolon |
bool | true | New line after ; statement terminator |
casing
Controls keyword and identifier casing.
| Key | Type | Default | Description |
|---|---|---|---|
reservedKeywords |
"UPPERCASE" | "lowercase" | "AsIs" |
"UPPERCASE" |
T-SQL reserved words (SELECT, FROM, …) |
builtInFunctions |
"UPPERCASE" | "lowercase" | "AsIs" |
"UPPERCASE" |
Built-in functions (ISNULL, GETDATE, …) |
builtInDataTypes |
"UPPERCASE" | "lowercase" | "AsIs" |
"lowercase" |
Data type keywords (int, varchar, …) |
systemObjects |
"UPPERCASE" | "lowercase" | "AsIs" |
"lowercase" |
System catalog objects (sys.objects, …) |
globalVariables |
"UPPERCASE" | "lowercase" | "AsIs" |
"lowercase" |
@@ROWCOUNT, @@ERROR, etc. |
localVariables |
"UPPERCASE" | "lowercase" | "AsIs" |
"AsIs" |
@param, @localVar — preserve original |
identifiers |
"UPPERCASE" | "lowercase" | "AsIs" |
"AsIs" |
Table/column/procedure names |
syncWithDatabase |
bool | false | Match identifier casing from live schema cache |
camelCaseDictionary |
bool | true | Preserve known camelCase identifiers |
applyOnTyping |
bool | true | Apply casing corrections as you type |
list
Controls how lists of items (SELECT columns, parameters, etc.) are laid out.
| Key | Type | Default | Description |
|---|---|---|---|
commaPosition |
"trailing" | "leading" |
"trailing" |
Comma after (col,) or before (,col) each item |
alignItemsAcrossClauses |
bool | true | Align SELECT/INSERT columns vertically |
alignAliases |
bool | true | Align AS alias expressions |
oneItemPerLine |
bool | true | Each list item on its own line |
collapseShortLists |
bool | true | Keep short lists on one line |
collapseThreshold |
int | 60 | Max characters for a list to be kept on one line |
indentListItems |
bool | true | Indent list items relative to clause keyword |
alignDataTypesInDDL |
bool | true | Align data-type columns in CREATE TABLE |
alignValuesInInsert |
bool | true | Align value columns in INSERT … VALUES |
spaceAfterListComma |
bool | true | Space after , in lists |
parenthesis
Controls formatting of parenthesized groups (subqueries, expressions, parameter lists).
| Key | Type | Default | Description |
|---|---|---|---|
openOnSameLine |
bool | true | ( on the same line as the preceding keyword |
closeOnNewLine |
"false" | "true" | "when_multiline" |
"false" |
When to place ) on its own line |
collapseShort |
bool | true | Keep short expressions on one line |
collapseThreshold |
int | 40 | Max characters to collapse onto one line |
indentContents |
bool | true | Indent contents inside parentheses |
spaceInside |
bool | false | Spaces inside ( expr ) |
removeRedundant |
bool | false | Remove unnecessary parentheses |
createTableColumns |
"newLine" | "sameLine" |
"newLine" |
Column list style in CREATE TABLE |
procedureParameters |
"newLine" | "sameLine" |
"newLine" |
Parameter list in CREATE PROCEDURE |
subqueryStyle |
"indent" | "aligned" |
"indent" |
Subquery indentation style |
dml
Controls DML (SELECT, INSERT, UPDATE, DELETE, MERGE) statement layout.
| Key | Type | Default | Description |
|---|---|---|---|
selectItemsOnNewLine |
bool | true | Each SELECT column on its own line |
selectStarOnSameLine |
bool | true | SELECT * stays on one line |
fromOnNewLine |
bool | true | FROM clause starts on a new line |
whereOnNewLine |
bool | true | WHERE clause starts on a new line |
andOrNewLine |
"before" | "after" | "sameLine" |
"before" |
Where to break before/after AND/OR |
andOrIndent |
"alignWithWhere" | "indent" |
"alignWithWhere" |
Indent of AND/OR relative to WHERE |
groupByOnNewLine |
bool | true | GROUP BY on a new line |
havingOnNewLine |
bool | true | HAVING on a new line |
orderByOnNewLine |
bool | true | ORDER BY on a new line |
topOnSameLine |
bool | true | TOP (n) stays on the SELECT line |
distinctOnSameLine |
bool | true | DISTINCT stays on the SELECT line |
intoOnNewLine |
bool | true | INTO in SELECT INTO on a new line |
valuesOnNewLine |
bool | true | VALUES on a new line in INSERT |
setOnNewLine |
bool | true | SET on a new line in UPDATE |
deleteFromOnSameLine |
bool | true | FROM on same line as DELETE |
mergeWhenOnNewLine |
bool | true | WHEN MATCHED / WHEN NOT MATCHED on new lines |
collapseShortStatements |
bool | true | Collapse simple statements to one line |
collapseThreshold |
int | 80 | Max characters for a statement to collapse |
collapseShortSubqueries |
bool | true | Collapse short subqueries to one line |
subqueryCollapseThreshold |
int | 60 | Max characters for subquery collapse |
join
Controls JOIN clause formatting.
| Key | Type | Default | Description |
|---|---|---|---|
onNewLine |
bool | true | JOIN on a new line |
indentJoin |
bool | false | Indent JOIN relative to FROM |
onConditionNewLine |
bool | true | ON clause on a new line |
onConditionIndent |
"indent" | "alignWithJoin" |
"indent" |
Indentation of ON condition |
multipleOnConditions |
"newLine" | "sameLine" |
"newLine" |
Multiple AND conditions in ON |
emptyLineBeforeJoin |
bool | false | Blank line before each JOIN |
alignJoinKeyword |
"left" | "right" | "center" |
"right" |
Align join type keywords (LEFT, INNER, etc.) |
joinTypeStyle |
"explicit" | "implicit" |
"explicit" |
Always write explicit join type |
crossApplyNewLine |
bool | true | CROSS APPLY / OUTER APPLY on new line |
ddl
Controls DDL (CREATE TABLE, CREATE PROCEDURE, etc.) statement layout.
| Key | Type | Default | Description |
|---|---|---|---|
createTableColumnsOnNewLine |
bool | true | Each column definition on its own line |
alignDataTypes |
bool | true | Align data type in column definitions |
alignConstraints |
bool | true | Align inline constraints |
constraintsOnNewLine |
bool | false | Table constraints on separate lines |
inlineConstraintStyle |
"sameLine" | "newLine" |
"sameLine" |
Inline column constraints placement |
tableConstraintsSeparate |
bool | true | Empty line before table-level constraints |
firstParameterOnNewLine |
"auto" | "always" | "never" |
"auto" |
First procedure parameter placement |
parameterAlignment |
"aligned" | "hanging" |
"aligned" |
Parameter list alignment |
alignParameterDataTypes |
bool | true | Align data types in parameter lists |
alignParameterDefaults |
bool | true | Align default values in parameter lists |
asOnNewLine |
bool | true | AS keyword on a new line in CREATE |
beginOnNewLine |
bool | true | BEGIN on a new line |
collapseShortDdl |
bool | true | Collapse simple DDL to one line |
collapseThreshold |
int | 60 | Max characters for DDL collapse |
controlFlow
Controls BEGIN/END, IF/ELSE, TRY/CATCH, and WHILE formatting.
| Key | Type | Default | Description |
|---|---|---|---|
beginOnNewLine |
bool | true | BEGIN on its own line |
endOnNewLine |
bool | true | END on its own line |
indentBetweenBeginEnd |
bool | true | Indent statements between BEGIN and END |
collapseShortIfElse |
bool | true | Collapse simple IF to one line |
collapseThreshold |
int | 60 | Max characters for IF collapse |
elseOnNewLine |
bool | true | ELSE on a new line |
elseAlignWithIf |
bool | true | Align ELSE with its IF |
tryCatchOnNewLine |
bool | true | TRY/CATCH blocks on new lines |
case
Controls CASE … WHEN … THEN … ELSE … END expression layout.
| Key | Type | Default | Description |
|---|---|---|---|
whenOnNewLine |
bool | true | Each WHEN on a new line |
thenOnNewLine |
bool | false | THEN on the same line as WHEN |
elseOnNewLine |
bool | true | ELSE on a new line |
endOnNewLine |
bool | true | END on a new line |
indentWhen |
bool | true | Indent WHEN branches |
alignThen |
bool | true | Align THEN values vertically |
collapseShortCase |
bool | true | Collapse simple CASE to one line |
collapseThreshold |
int | 60 | Max characters for CASE collapse |
cte
Controls Common Table Expression (CTE) formatting.
| Key | Type | Default | Description |
|---|---|---|---|
withOnNewLine |
bool | true | WITH on a new line before the first CTE |
cteBodyIndent |
bool | true | Indent the body of each CTE |
commaBeforeCte |
bool | false | Leading comma before each CTE name |
emptyLineBetweenCtes |
bool | true | Blank line between consecutive CTEs |
expression
Controls expression and predicate formatting.
| Key | Type | Default | Description |
|---|---|---|---|
booleanOperatorNewLine |
"before" | "after" | "sameLine" |
"before" |
Break before or after AND/OR |
betweenOnOneLine |
bool | true | BETWEEN x AND y on one line |
inListStyle |
"multiLine" | "sameLine" |
"multiLine" |
IN (a, b, c) — one line or multiple |
inListThreshold |
int | 60 | Max characters before IN list breaks |
existsSubqueryIndent |
"indent" | "hanging" |
"indent" |
Indentation of subquery in EXISTS(...) |
actions (Format Action Config)
Controls which transformations are applied during Format Document / Format Action operations.
| Key | Type | Default | Description |
|---|---|---|---|
applyLayout |
bool | true | Apply all whitespace and line-break rules |
applyCasing |
bool | true | Apply casing rules |
insertSemicolons |
bool | false | Add missing ; statement terminators |
removeSemicolons |
bool | false | Remove all ; terminators |
expandWildcards |
bool | false | Replace SELECT * with explicit column list (requires schema) |
qualifyObjectNames |
bool | false | Add schema prefix to unqualified names |
addAsKeyword |
bool | true | Add AS to implicit aliases |
addSquareBrackets |
bool | false | Wrap all identifiers in square brackets |
SQL Prompt Style Interop (Spec 020)
.sqlpromptstylev2 (Redgate SQL Prompt's distributed XML format) is supported for both import and export, allowing teams to standardise across SQL Prompt and AKML installs.
Import — SqlPromptImporter.Import(xmlContent) in src/AkmlSql.Formatting/Profiles/SqlPromptImporter.cs. Handles both <Options><Option Name= Value=> and flat-element XML shapes. Returns a SqlPromptImportResult with the imported FormattingProfile plus MappedCount / UnmappedCount / UnmappedOptions[] so the editor can surface unsupported settings.
Export — SqlPromptExporter.Export(profile) in src/AkmlSql.Formatting/Profiles/SqlPromptExporter.cs. Round-trip safe: every setting in SqlPromptImporter.OptionMap has a parallel inverse getter in SqlPromptExporter.ReverseMap. Settings AKML supports but SQL Prompt has no equivalent for are omitted from the export.
Round-trip test definition (SC-007 / Q1 clarification): for each (input.sql × style.sqlpromptstylev2) pair, AKML's formatted output is compared to SQL Prompt's golden output as follows:
- Strip trailing whitespace per line
- Normalise line endings to
\n(LF) - Drop UTF-8 BOM if present
- Then require byte-exact equality
A pair passes iff the two normalised byte streams are equal. The corpus suite passes iff ≥ 95 % of pairs pass. See tests/format-parity/README.md for the corpus layout.
Format Settings Schema — the canonical descriptor consumed by the Format Styles editor lives at src/AkmlSql.Formatting/Profiles/FormatSettingSchema.cs. Built by reflection over FormattingProfile's 12 sub-category POCOs, exposed to the shell via the RequestStyleEditorSchema IPC (see doc/ipc-api.md).
Format Actions (IPC)
Format operations can target specific transformations using the FormatActionType enum
(src/AkmlSql.Core/Ipc/Messages/FormatActionRequest.cs; the values are wire codes, never renumber them):
| Value | Name | Description |
|---|---|---|
| 0 | CasingOnly |
Apply the style's casing, no layout changes |
| 1 | InsertSemicolons |
Add missing statement terminators |
| 2 | RemoveSemicolons |
Remove statement-terminating ; |
| 3 | ExpandWildcards |
Replace SELECT * with the column list (needs the schema cache) |
| 4 | QualifyObjectNames |
Add the owning schema to unqualified table names, skipping ambiguous ones (needs the schema cache) |
| 5 | AddSquareBrackets |
Bracket identifiers |
| 6 | RemoveSquareBrackets |
Remove square brackets from identifiers |
| 7 | AddAsKeyword |
Add AS to implicit aliases |
| 8 | RemoveAsKeyword |
Remove AS from aliases |
| 9 | ExpandInsertColumns |
Add the column list to an INSERT that has none (needs the schema cache) |
| 10 | ExpandExecParameters |
Turn positional EXEC arguments into named @param = value ones (needs the schema cache) |
| 11 | ExpandUpdateColumns |
Add the target table's missing columns to an UPDATE's SET list, as NULL |
| 12 | ConvertOldStyleJoins |
Rewrite comma joins as INNER JOIN ... ON (non-equi predicates stay in WHERE) |
| 13 | AddGroupByColumns |
Add a GROUP BY listing the non-aggregated columns |
| 14 | EncapsulateBeginEnd |
Wrap the selection (or the batch) in BEGIN ... END |
| 15 | ReplaceDeprecatedSyntax |
Replace deprecated syntax (for example != with <>) |
| 16 | ConvertSpExecutesql |
Turn an sp_executesql call into static SQL by substituting its parameter values |
| 17 | Unformat |
Collapse non-significant whitespace into compact SQL |
Bulk Formatting
The BulkFormatter applies formatting to multiple files in parallel (up to Environment.ProcessorCount threads). Configuration:
confirmBulkFormat: show confirmation dialog before startingcreateBackups: write.bakfiles alongside originalshandleParseErrors: skip files with parse errors instead of abortingrespectNoformat: honour-- noformatregions in all files
Bulk format can be cancelled mid-operation via the BulkFormatCancel IPC message.
Diagnostic Codes
The formatter may emit diagnostics alongside the formatted output:
| Code | Level | Description |
|---|---|---|
FMT001 |
Warning | Semantic validation failed — original SQL returned unchanged |
FMT002 |
Warning | Idempotency check failed — re-formatting would change the output |
FMT003 |
Information | Parse error in file — skipped during bulk format |
FMT004 |
Information | File skipped — entirely inside a -- noformat region |