Documentation
¶
Overview ¶
Package diagnostics defines the user-facing error model shared by every compiler phase. All user mistakes surface as Diagnostics with stable codes; bare Go errors are reserved for environmental failures.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func HasErrors ¶
func HasErrors(diags []Diagnostic) bool
HasErrors reports whether any diagnostic is of Error severity.
func LineCol ¶
LineCol converts a byte offset into 1-based line and column (column counts bytes; rune-aware columns arrive with the P7 renderer). It builds a one-shot line index; callers rendering many diagnostics for the same source should build a LineMap once and reuse it (see PrintDiags) to avoid O(offset) per lookup.
func Sort ¶
func Sort(diags []Diagnostic)
Sort orders diagnostics by (file, offset, code) for stable output.
Types ¶
type Code ¶
type Code string
Code is a stable diagnostic identifier (e.g. "SQLETCH001"). Ranges: 0xx lexical/structural (scanner), 1xx rules, 2xx oracle, 3xx codegen/config.
const ( CodeConstructGrammar Code = "SQLETCH001" // malformed/unterminated construct CodeBadIdentifier Code = "SQLETCH002" // guard/case/param names must be snake_case CodeMissingHeader Code = "SQLETCH003" // statement without -- name: header CodeDuplicateQueryName Code = "SQLETCH004" CodeMultipleStatements Code = "SQLETCH005" CodeConstructNested Code = "SQLETCH006" // construct inside parens/subquery CodeConstructBadSlot Code = "SQLETCH007" // construct at a non-slot clause CodeConjunctNeedsAnd Code = "SQLETCH008" CodeChooseStructure Code = "SQLETCH009" CodeTooManyGuards Code = "SQLETCH010" CodePositionalParam Code = "SQLETCH011" CodeConstructNesting Code = "SQLETCH012" // guard inside guard (R5) CodeTooManyParams Code = "SQLETCH013" // more parameters than the bind plan's int16 index holds CodeWhenIntLiteral Code = "SQLETCH014" // @when integer literal is ambiguous (leading zero) or out of int64 range CodeWhenStringLiteral Code = "SQLETCH015" // @when string literal is not a plain single-quoted SQL string (delimiters/escapes would survive into the generated guard) )
Scanner-phase codes (see docs/design/01-template-scanner.md).
const ( CodeGoParse Code = "SQLETCH020" // the .go file does not parse CodeGoMarkerTarget Code = "SQLETCH021" // //sqletch:query on a non-const declaration CodeGoNotRawString Code = "SQLETCH022" // marked const's value is not a raw string literal CodeGoBadConstSpec Code = "SQLETCH023" // marked const has no value, or names/values disagree )
Go-source input codes: templates authored in a `//sqletch:query` const inside a .go file (see docs/design/13-go-source-input.md). They sit in the scanner band because they report on the same phase — getting template bytes out of a file and into the scanner.
const ( CodeRenderingParse Code = "SQLETCH100" // a rendering fails to parse CodeJoinTypeForbidden Code = "SQLETCH101" // optional join not INNER/LEFT (R2) CodeNodeIncomplete Code = "SQLETCH102" // fragment is not one complete node (R1) CodeNotSingleDML Code = "SQLETCH103" // not exactly one SELECT/UPDATE/INSERT/DELETE CodeVacuousGuard Code = "SQLETCH110" // required param used as guard (R9) CodeGuardNeverBinds Code = "SQLETCH111" // guard param binds nowhere under itself (R9) CodeChooseParamBinds Code = "SQLETCH112" // @choose control param used as :name (R9) CodeUnanchoredClause Code = "SQLETCH113" // all conjuncts optional, no anchor (R6) CodeAmbiguousRef Code = "SQLETCH114" // unqualified ref matches several relations CodeScopeViolation Code = "SQLETCH115" // reference into optional join w/o guard (R3) CodePlannerSensitive Code = "SQLETCH116" // e.g. FOR UPDATE + optional LEFT JOIN CodeStarExpansion Code = "SQLETCH117" // SELECT * would include optional-join columns (R2) CodeUnanchoredSet Code = "SQLETCH118" // every SET/INSERT-list item optional, no anchor (R6) CodePairedGuards Code = "SQLETCH119" // INSERT column/value guard pairing broken (R7) CodeInParamScalarMix Code = "SQLETCH120" // an @in list param also bound as a plain scalar (R9) CodeOrderByDistinct Code = "SQLETCH122" // @order-by under DISTINCT ON (prefix-sensitive) CodeOrderByNeedsDflt Code = "SQLETCH123" // WITH TIES requires an @order-by @default CodePolicyUnscoped Code = "SQLETCH124" // designated table without the scoping conjunct in every shape CodePolicyUnweavable Code = "SQLETCH125" // a policy applies but cannot be woven into this query CodePolicyBadOptOut Code = "SQLETCH126" // @policy-optout names an unknown or inapplicable policy )
Rules-phase codes (R1 runs in P2's pipeline position; see docs/design/02-rendering.md and 03-structural-rules.md).
const ( CodeServerVersionMismatch Code = "SQLETCH200" // pinned version != connected server CodeIndeterminateParam Code = "SQLETCH201" // undetermined parameter type (add a cast) CodeOracleFailure Code = "SQLETCH202" // prepare/describe failed CodeCacheServerDrift Code = "SQLETCH203" // committed cache was generated against a different server version CodeDestructiveReset Code = "SQLETCH204" // refused to reset a user-supplied database's schema (pass --allow-destructive) CodeColumnAgreement Code = "SQLETCH210" // renderings disagree on result columns CodeParamAgreement Code = "SQLETCH211" // renderings disagree on a param's type CodeOptionalInsertNotNull Code = "SQLETCH212" // optional NOT NULL column without default (warning) CodeParamHintConflict Code = "SQLETCH213" // `-- @param` hint disagrees with the oracle (Tier 1) CodeNativeUnsupported Code = "SQLETCH214" // native oracle: query construct outside the modeled subset CodeNativeDDL Code = "SQLETCH215" // native oracle: schema DDL outside the catalog builder's subset CodeColumnHintConflict Code = "SQLETCH216" // `-- @column` hint disagrees with the oracle's column type )
Oracle-phase codes (see docs/design/04-type-oracle.md).
const ( CodeConfigParse Code = "SQLETCH300" // sqletch.yaml unreadable/unknown keys CodeConfigInvalid Code = "SQLETCH301" // sqletch.yaml field validation CodeExpansionLarge Code = "SQLETCH302" // static expansion exceeds max_shapes CodePolicyInvalid Code = "SQLETCH303" // a policy declaration is malformed CodeShapeCapReached Code = "SQLETCH304" // shape enumeration stopped at its cap (explain --max-shapes, verification.max_shapes) CodePathEscape Code = "SQLETCH306" // cache.path/output.path escapes the project directory // A result column's name does not form a valid Go identifier once // mapped (an oracle column or quoted alias carrying spaces, braces, // punctuation, …): emitting it verbatim would either fail gofmt with // no span or, worse, splice attacker-influenced text into the // generated package. Refuse it and ask for an `AS` alias / `-- @column`. CodeInvalidColumnIdentifier Code = "SQLETCH307" CodeSourceUnreadable Code = "SQLETCH308" // a glob-matched template file could not be read (LSP degrades past it) CodeNameCollision Code = "SQLETCH310" // generated Go identifiers collide CodeUnsupportedType Code = "SQLETCH311" // no Go mapping for a database type // null_overrides hygiene: overrides are the analyzer's escape // hatch and are applied by RESULT-COLUMN NAME, so a key that // matches nothing is dead config and a key matching several // same-named columns forces all of them at once. CodeOverrideUnknownColumn Code = "SQLETCH312" // null_overrides names no result column of the query CodeOverrideAmbiguousColumn Code = "SQLETCH313" // null_overrides matches multiple same-named result columns // Multi-target resolution (docs/design/19-multi-target-output.md §4). // A template file belongs to exactly one generated package, and an // output directory to exactly one package name — otherwise "which // package is this query in" has no answer, and generate would emit // two packages over one directory. CodeTargetFileOverlap Code = "SQLETCH314" // a template file is claimed by two targets CodeTargetCollision Code = "SQLETCH315" // two targets resolve to one path with different packages CodeTargetNoMatch Code = "SQLETCH316" // a queries pattern matched no file (warning) CodeTargetNameSpan Code = "SQLETCH317" // an overrides/static_expansion name exists in several targets (warning) )
Codegen/config codes.
type Diagnostic ¶
func (Diagnostic) Render ¶
func (d Diagnostic) Render(src []byte) string
Render produces the human-readable one-line form "file:line:col: error[CODE]: message". The full excerpt renderer arrives in P7; this form is enough for tests and early CLI output.
func (Diagnostic) RenderExcerpt ¶
func (d Diagnostic) RenderExcerpt(src []byte) string
RenderExcerpt produces the multi-line form with a source excerpt and caret underline (design 07 §3):
file:12:7: error[SQLETCHnnn]: message | 12 | AND organization_id = :org | ^^^^^^^^^^^^^^^ help: …
func (Diagnostic) RenderExcerptWith ¶
func (d Diagnostic) RenderExcerptWith(src []byte, lm *LineMap) string
RenderExcerptWith is RenderExcerpt reusing a precomputed line index (see RenderWith / PrintDiags). Output is byte-identical to RenderExcerpt.
func (Diagnostic) RenderWith ¶
func (d Diagnostic) RenderWith(src []byte, lm *LineMap) string
RenderWith is Render reusing a precomputed line index. Rendering a batch of diagnostics for one file builds the index once (O(n)) and then locates each diagnostic in O(log lines) instead of O(offset) — see PrintDiags. Output is byte-identical to Render.
func (Diagnostic) WithHint ¶
func (d Diagnostic) WithHint(format string, args ...any) Diagnostic
type LineMap ¶
type LineMap struct {
// contains filtered or unexported fields
}
LineMap is a precomputed index of line-start byte offsets for one source, so byte offset → (line, col) is an O(log lines) binary search instead of an O(offset) rescan. Rendering d diagnostics for an n-byte file drops from O(n·d) to O(n + d·log lines) by building it once.
func (*LineMap) LineCol ¶
LineCol returns the 1-based line and (byte-)column of off. It is byte-identical to the previous linear implementation: an offset past EOF clamps to EOF, the column counts bytes since the last '\n', and a '\n' byte itself belongs to the line it terminates.
func (*LineMap) LineStartOffset ¶
LineStartOffset returns the byte offset at which the 0-based line begins. A line index at or past the last line clamps to len(src), so a position past EOF resolves to EOF — matching the previous linear walk that returned len(src) when the requested line ran off the end.