Documentation
¶
Overview ¶
Package dialect defines the driver interfaces separating the dialect-agnostic core from database specifics. v0.1 ships only the LexerProfile half; Frontend/Oracle land in P2/P4.
Index ¶
- func EntryFromDesc(fp, renderedSQL string, d Desc) *cache.OracleEntry
- func FoldIdent(profile LexerProfile) func(string) string
- func InEmptyOf(profile LexerProfile) string
- func ShiftOracleErrPos(err error, delta int) error
- type CTEDef
- type CaseInsensitiveIdents
- type ColRef
- type ColumnDesc
- type Desc
- type Frontend
- type GoTypeRef
- type InEmpty
- type JoinType
- type LexError
- type LexerProfile
- type NativeUnsupportedError
- type Oracle
- type OracleError
- type ParseError
- type PlaceholderStyle
- type Placeholders
- type RelRef
- type StmtKind
- type SubRel
- type TableRef
- type TargetItem
- type Token
- type TokenKind
- type Tree
- type TypeMap
- type TypeRef
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func EntryFromDesc ¶
func EntryFromDesc(fp, renderedSQL string, d Desc) *cache.OracleEntry
EntryFromDesc converts a Describe answer into its committed-cache form. This is the single Desc→entry conversion: the pipeline and the oracle corpus harness must serialize identically, or cache byte-identity across oracle backends (design 15 §3) stops being checkable.
func FoldIdent ¶
func FoldIdent(profile LexerProfile) func(string) string
FoldIdent returns the profile's identifier-folding function: on a case-insensitive dialect it maps an identifier to its case-folded form, elsewhere it is the identity. The resolution-based rules (R3 guard scope, R2 qualified star) run every qualifier, alias, scope name, and catalog column name through it so a mixed-case reference cannot slip past a guard check on a dialect that would resolve it at runtime (SQLETCH115/117). Fold both sides of every comparison.
func InEmptyOf ¶
func InEmptyOf(profile LexerProfile) string
InEmptyOf resolves a profile's arity-0 @in emission.
func ShiftOracleErrPos ¶
ShiftOracleErrPos returns err with an *OracleError's Pos moved left by delta bytes. The plan oracles measure error positions against an EXPLAIN-wrapped string (a delta-byte prefix + the rendering), but pipeline diagnostics map Pos straight through the rendering's source map, so the prefix must be stripped for the position to be rendering-relative like the Describe path's. A Pos landing inside the stripped prefix, or a non-positional error, is reported unpositioned (Pos = -1) rather than mis-attributed; a non-*OracleError is returned unchanged.
Types ¶
type CTEDef ¶
type CTEDef struct {
Name string
Recursive bool
// Tree is the facade over the body, nil when the body is not a
// plain query (a data-modifying CTE): such bodies expose only
// RETURNING rows via a target list the engine attributes to the
// base tables the DML reads.
Tree Tree
// PoisonTables lists every base-table name a data-modifying body
// (nil Tree) mentions. PostgreSQL attributes a wCTE column through
// GetCTETargetList — the RETURNING list — to a base table's OID,
// and that table may sit on a null-extended side of a join inside
// the DML (e.g. RETURNING a RIGHT JOIN's null-extended side). The
// analyzer must POISON these OIDs so no clean OUTER instance of the
// same table can vouch for the null-extended provenance (design 05
// §2b). Populated only by the PostgreSQL facade — MySQL/SQLite CTE
// bodies are SELECT-only, so it stays nil there.
PoisonTables []TableRef
}
CTEDef is one WITH-list definition.
type CaseInsensitiveIdents ¶
type CaseInsensitiveIdents interface {
CaseInsensitiveIdents() bool
}
CaseInsensitiveIdents is implemented by lexer profiles whose dialect resolves identifier references case-insensitively: an alias written `A` is matched by a reference `a`, and a column `Kind` by `kind` (MySQL, SQLite). PostgreSQL case-folds unquoted identifiers at parse time, so its facade already yields folded names — it leaves this unimplemented and folding is then the identity.
type ColRef ¶
type ColRef struct {
Fields []string // qualified parts, e.g. ["u", "id"] or ["id"]
Star bool // reference ends in * (e.g. u.*)
Loc int // byte offset in the parsed SQL
InSubquery bool // inside a sublink/derived table/CTE scope
// ScopeAliases is the set of effective relation names (alias if
// present, else table name) introduced by the subquery scope(s)
// ENCLOSING this reference — the union across every enclosing
// subquery level, but NOT the top-level statement's own FROM. It is
// nil for a top-level reference. R3 uses it to resolve a qualified
// reference innermost-first: a qualifier found here is bound by a
// nearer scope (SQL resolves innermost-first), so the reference does
// not touch a same-named top-level relation and its guard need not
// be re-derived. A correlated reference — whose qualifier is a
// top-level relation absent from every enclosing subquery FROM — is
// NOT listed here and is still checked. Facades under-collect rather
// than over-collect (set-operation branch FROMs are omitted): a
// missing name only preserves the pre-existing (sound) check, an
// extra name would wrongly suppress one.
ScopeAliases []string
}
ColRef is one column reference anywhere in the statement.
type ColumnDesc ¶
ColumnDesc describes one result column. SrcRel/SrcAtt tie a direct column reference back to its catalog column (0 when the column is a computed expression) — the nullability analysis keys on this.
type Desc ¶
type Desc struct {
Params []TypeRef // by placeholder position ($1 = [0])
Columns []ColumnDesc
}
Desc is the oracle's answer for one rendering.
func DescFromEntry ¶
func DescFromEntry(e *cache.OracleEntry) Desc
DescFromEntry is EntryFromDesc's inverse, used on cache hits.
type Frontend ¶
type Frontend interface {
Parse(sql string) (Tree, error)
ProbeExpr(expr string) error
ProbeJoinItem(item string) error
ProbeOrderBy(clause string) error
ProbeOrderByKey(expr string) error
ProbeGroupBy(clause string) error
ProbeSetItem(item string) error
ProbeInsertValue(expr string) error
}
Frontend parses rendered SQL and answers node-completeness probes (design 02 §4). Probe methods return nil when the fragment forms exactly one complete node of its slot.
type GoTypeRef ¶
GoTypeRef is a Go type for a database type, plus the import it needs ("" for builtins).
type InEmpty ¶
type InEmpty interface {
InEmptySQL() string
}
InEmpty is implemented by expanding-dialect profiles to provide the arity-0 @in emission: a fragment completing `expr <here>` so that an empty list matches nothing — FALSE even for a NULL operand, matching PostgreSQL's `= ANY('{}')`.
type LexError ¶
LexError is returned for unterminated strings/comments; the scanner converts it into a diagnostic at Pos.
type LexerProfile ¶
type LexerProfile interface {
// NextToken lexes the token starting at src[pos:]. pos is
// guaranteed to be a token boundary. At end of input it returns
// a token with Kind == KindEOF.
NextToken(src []byte, pos int) (Token, error)
}
LexerProfile lets the shared template scanner walk dialect SQL without parsing it. Implementations only need correct token *boundaries* (strings, comments, params, operators), not SQL understanding.
type NativeUnsupportedError ¶
type NativeUnsupportedError struct {
Pos int // byte offset into the described SQL (-1 unknown)
Construct string // what was refused, human-readable
Hint string // the compliant rewrite, if one exists
}
NativeUnsupportedError is a native-backend refusal: the input is outside the backend's modeled subset (design 15 §2 — refuse, never guess). Distinct from OracleError, which mirrors a rejection the real engine would also make; the CLI maps this to SQLETCH214 and the differential harness treats it as the tolerable direction only.
func (*NativeUnsupportedError) Error ¶
func (e *NativeUnsupportedError) Error() string
type Oracle ¶
type Oracle interface {
// Describe prepares (never executes) sql and reports parameter and
// result column types.
Describe(ctx context.Context, sql string) (Desc, error)
// Plan runs the dialect's plan-only statement (EXPLAIN) to surface
// planner-stage errors that prepare cannot see.
Plan(ctx context.Context, sql string) error
// Snapshot dumps the catalog portions needed for offline analysis.
Snapshot(ctx context.Context) (*cache.Catalog, error)
ServerVersion(ctx context.Context) (string, error)
}
Oracle is the type oracle: it answers what the database itself knows about a rendering. Backends (server, embedded engine, native inference) implement the same interface — see the Oracle backends section of docs/spec.md.
type OracleError ¶
OracleError reports a prepare/describe failure. Pos is a byte offset into the described SQL (-1 when unknown). Indeterminate is set for "could not determine data type of parameter" failures — the CLI attaches the explicit-cast hint (SQLETCH201).
func (*OracleError) Error ¶
func (e *OracleError) Error() string
type ParseError ¶
ParseError reports a dialect parse failure at a byte offset into the parsed SQL (rendered text; callers map it back to the template).
func (*ParseError) Error ¶
func (e *ParseError) Error() string
type PlaceholderStyle ¶
type PlaceholderStyle int
PlaceholderStyle is how a dialect binds parameters in prepared SQL.
const ( // PlaceholderDollar: $1, $2, … numbered in first-occurrence order; // repeated references to one bind source reuse the number // (PostgreSQL). PlaceholderDollar PlaceholderStyle = iota // PlaceholderQuestion: '?', one placeholder per occurrence; // repeated references repeat the bind (MySQL, SQLite). PlaceholderQuestion )
func StyleOf ¶
func StyleOf(profile LexerProfile) PlaceholderStyle
StyleOf resolves a profile's placeholder style.
type Placeholders ¶
type Placeholders interface {
PlaceholderStyle() PlaceholderStyle
}
Placeholders is implemented by lexer profiles to declare their dialect's bind-placeholder style. Profiles that do not implement it default to PlaceholderDollar.
type RelRef ¶
type RelRef struct {
Alias string // alias if present, else ""
Table string // relation name ("" for subselects etc.)
Schema string // explicit schema/database qualifier, "" when unqualified
// Only marks a `FROM ONLY table` reference (PostgreSQL): the scan
// excludes inheritance children, so child rows cannot undermine
// the parent's NOT NULL declarations.
Only bool
Loc int // byte offset of the relation in the parsed SQL
Join JoinType
// NullableSide reports whether this relation sits on a
// null-extended side of an outer join in this statement (right of
// LEFT, left of RIGHT, either side of FULL) — the nullability
// analysis input.
NullableSide bool
}
RelRef is one relation of the statement's FROM/target clauses.
type SubRel ¶
type SubRel struct {
Alias string
NullableSide bool // on a null-extended side of the ENCLOSING level
Tree Tree
}
SubRel is one FROM-reachable derived table, wrapped in its own Tree facade so the nullability analyzer can recurse instead of distrusting the whole statement (design 05 §2b).
type TableRef ¶
type TableRef struct {
Name string
Schema string // explicit schema/database qualifier, "" when unqualified
Loc int
}
TableRef is one base-table name referenced anywhere in the statement, including subquery and CTE bodies — the policy weaver's visibility input (design 14 §11.1) and the nullability analyzer's poisoning input (design 05 §2b). References to CTE *names* are deliberately included: a CTE shadowing a policy-designated table is conservatively treated as touching it (a false positive is a loud diagnostic with an opt-out, never a silent leak). Loc is -1 where the parser exposes no offset.
type TargetItem ¶
type TargetItem struct {
Name string // output alias ("" if none)
Star bool // item is * or qualifier.*
Qualifier string // "u" for u.*; "" for bare *
FuncName string // lowercased function name when the item is a bare call
// Total marks an expression that can never evaluate to NULL
// regardless of data: a non-NULL literal, EXISTS, an IS [NOT]
// NULL / boolean test, a non-null value function, a cast of a
// total expression, or coalesce with at least one total argument.
// Data-INDEPENDENT only — a column reference never makes an
// expression total (its nullability is the analyzer's job).
Total bool
// AggArg is the qualified path of the call's single bare-column
// argument (["u","org_id"] or ["org_id"]) when the item is a
// plain aggregate call over exactly one column with no FILTER
// clause and no OVER clause; nil otherwise. The nullability
// analyzer combines it with GROUP BY presence: an aggregate over
// a non-nullable column of a non-null-extended relation is
// non-null when every output row's group is non-empty.
AggArg []string
Loc int
}
TargetItem is one projection entry.
type TokenKind ¶
type TokenKind int
const ( KindEOF TokenKind = iota KindWhitespace KindLineComment KindBlockComment KindString // includes dollar-quoted and E” strings KindQuotedIdent // "ident" KindIdent KindNumber KindParamRef // :name (Text includes the colon) KindPositionalParam // $1, $2, … KindCast // :: KindOperator KindLParen KindRParen KindComma KindSemicolon KindOther // ., [, ], and anything else structurally irrelevant )
type Tree ¶
type Tree interface {
StmtCount() int
Kind() StmtKind
Relations() []RelRef
// DeepTables reports every base-table name referenced anywhere in
// the statement — subqueries and CTE bodies included, unlike
// Relations, which stops at the statement's own FROM/target
// clauses. The policy weaver compares the two to reject designated
// tables in positions it cannot scope (design 14 §D6).
DeepTables() []TableRef
ColumnRefs() []ColRef
TargetItems() []TargetItem
// TopConjunctLocs returns the byte locations of the statement's
// top-level WHERE conjuncts (AND-flattened).
TopConjunctLocs() []int
// HavingConjunctLocs is TopConjunctLocs for the statement-level
// HAVING clause (empty when the statement has none).
HavingConjunctLocs() []int
// OrderByLocs returns byte locations of statement-level ORDER BY
// item expressions.
OrderByLocs() []int
HasDistinctOn() bool
HasLockingClause() bool
// HasFetchWithTies reports FETCH FIRST … WITH TIES, which makes
// the ORDER BY clause mandatory (@order-by then needs a @default).
HasFetchWithTies() bool
// HasSetOperation reports a statement-level set operation
// (UNION/INTERSECT/EXCEPT, SQLite compound selects). Engines may
// attribute set-op output to a branch's base table (SQLite: the
// FIRST branch), which no per-branch analysis can license —
// SrcRel narrowing is off for the level (design 05 §2b).
HasSetOperation() bool
// DerivedRels returns the statement's own FROM-reachable derived
// tables, each wrapped in a sub-facade for recursive analysis.
DerivedRels() []SubRel
// CTEs returns the statement's WITH-list definitions in order.
CTEs() []CTEDef
// HasUnresolvableProvenance reports that the ORACLE's column
// attribution for this statement can cross-resolve to a wrong
// catalog entry: MySQL/SQLite attribute by BARE table name with
// no database qualifier, so any db-qualified reference anywhere
// in the statement (subqueries included) poisons every
// name-keyed attribution. PostgreSQL attributes by OID and always
// reports false (design 05 §2a).
HasUnresolvableProvenance() bool
// HasGroupingSets reports ROLLUP / CUBE / GROUPING SETS in the
// statement-level GROUP BY: super-aggregate rows null out grouping
// columns regardless of catalog NOT NULL, so SrcRel-based
// narrowing is unsound while one is present (design 05 §2a).
HasGroupingSets() bool
// HasGroupBy reports a statement-level GROUP BY clause (of any
// form). With one present — and no grouping sets — every output
// row aggregates a NON-EMPTY group, which is what lets strict
// aggregates over non-nullable columns narrow (design 05 §3a).
HasGroupBy() bool
// NotNullConjuncts returns the bare column reference of every
// depth-0 statement-level WHERE conjunct of the exact form
// `col IS NOT NULL`. Loc is the conjunct's byte offset in the
// parsed SQL — the analyzer uses it to require the conjunct to be
// SKELETON text (present in every shape) before narrowing.
NotNullConjuncts() []ColRef
// HasConflictUpdate reports an INSERT whose conflict arm MODIFIES
// rows — PostgreSQL/SQLite `ON CONFLICT … DO UPDATE`, MySQL
// `ON DUPLICATE KEY UPDATE`. A `DO NOTHING` arm and every non-INSERT
// statement report false. The policy weaver refuses to weave such an
// upsert on a designated table (design 14 §D6, owner decision
// 2026-08-21): the DO UPDATE arm rewrites rows but cannot carry a
// woven WHERE that scopes the conflict, so refusal is the sound
// minimum.
HasConflictUpdate() bool
}
Tree is the narrow dialect-AST facade the rules engine consumes. Deliberately minimal: extending it is a compile-visible act.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package mysql implements the MySQL dialect driver (Tier 2).
|
Package mysql implements the MySQL dialect driver (Tier 2). |
|
Package postgres implements the PostgreSQL dialect driver.
|
Package postgres implements the PostgreSQL dialect driver. |
|
Package sqlite implements the SQLite dialect driver (Tier 2).
|
Package sqlite implements the SQLite dialect driver (Tier 2). |