Documentation
¶
Overview ¶
Package sqlglot is a Go port of sqlglot's expression model and parser, scoped to what a read-only SQL guard needs first and growing outward.
The architecture -- a tokenizer, a data-driven parser over dispatch tables, an expression tree in which every construct is a visible node, and dialects as override sets -- is Toby Mao's, from github.com/tobymao/sqlglot (MIT). See NOTICE for the reference commit this port is measured against.
Index ¶
- Variables
- func AnnotateFully(e *Expression, dialect string) bool
- func Anonymize(sql, dialect string) string
- func CanonicalSQL(sql, dialect string) (string, error)
- func Dialects() []string
- func Format(sql, dialect string) (string, error)
- func FormatScript(sql, dialect string) (string, error)
- func FunctionName(e *Expression, dialect string) (string, bool)
- func Generate(e *Expression, dialect string) (string, error)
- func IsIntegerType(t *Expression) bool
- func IsWrite(e *Expression) bool
- func SplitBatches(script, dialect string) ([]string, error)
- type Arg
- type BooleanSQL
- type ClassTrigger
- type CompositeTypeSQL
- type Config
- type DataTypeKind
- type DataTypeSpec
- type DiffEdit
- type EditKind
- type Expression
- func Annotate(e *Expression, dialect string) *Expression
- func ApplyIndexOffset(this *Expression, items []*Expression, offset int, dialect string) ([]*Expression, bool)
- func New(class string, args ...Arg) *Expression
- func ParseDataType(s, dialect string) (*Expression, error)
- func ParseJSONPath(path string) (*Expression, error)
- func ParseOne(sql, dialect string) (*Expression, error)
- func Simplify(e *Expression, dialect string) *Expression
- func (e *Expression) Append(key string, child *Expression)
- func (e *Expression) Copy() *Expression
- func (e *Expression) Dump() []map[string]any
- func (e *Expression) DumpJSON() []byte
- func (e *Expression) Equal(other *Expression) bool
- func (e *Expression) FindAll(classes ...string) []*Expression
- func (e *Expression) Name() string
- func (e *Expression) Set(key string, value any)
- func (e *Expression) This() *Expression
- func (e *Expression) Walk(fn func(*Expression) bool)
- type FormatString
- type FuncArg
- type FuncConst
- type FuncSQL
- type FuncSpec
- type GenerateError
- type JSONPathFunc
- type JSONPathSQL
- type JSONPerPart
- type KindSpec
- type NotAQueryError
- type Param
- type ParseDiagnostic
- type ParserTables
- type PlaceholderSQL
- type PropertySpec
- type Routine
- type ScriptResult
- type SyntaxTemplate
- type TableSampleSQL
- type Token
- type TokenError
- type TokenType
- type Tokenizer
- type TypeDispatch
- type UnsupportedError
- type ValueDispatch
Constants ¶
This section is empty.
Variables ¶
var ErrGenerate = errors.New("sqlglot-go: cannot generate SQL")
ErrGenerate reports a tree the generator cannot write.
A guard that rewrote a statement and then emitted something subtly different would be worse than one that refused, so an unknown node stops the rewrite rather than producing an approximation.
var ErrMultipleStatements = errors.New("sqlglot-go: more than one statement")
ErrMultipleStatements reports more than one statement in the input. A guard that permitted the first and ignored the rest would be no guard at all.
var ErrNotAQuery = errors.New("sqlglot-go: not a query")
ErrNotAQuery reports a statement the port recognises but does not parse: DDL and DML, which a read-only guard refuses on sight.
It is deliberately distinct from ErrUnsupported. The guard above this parser has to refuse `DROP TABLE t` for being a write, not for being unreadable -- the conformance suite checks the reason -- and naming the statement is all that takes. Building the tree would be work with no consumer: nothing here will ever execute one.
var ErrUnsupported = errors.New("sqlglot-go: unsupported statement")
ErrUnsupported reports a statement the port cannot parse yet.
It is deliberately distinct from a syntax error. The guard above this parser turns it into a refusal, and the differential harness counts it as a gap in coverage -- never as a match. A construct the port does not understand must never become a tree that merely looks plausible.
Functions ¶
func AnnotateFully ¶
func AnnotateFully(e *Expression, dialect string) bool
AnnotateFully stamps a type on every node of a subtree and reports whether every one of them had an answer.
It MUTATES, and that is the point: the reference's annotations are part of the tree it produces -- they are dumped, and the differential compares them -- so a port that computed a type without recording it would agree about the answer and disagree about the tree.
Where it returns false the port met a node it has no rule for. A caller that stamped UNKNOWN there would be recording its own ignorance as the reference's answer, which is why the subscript rule refuses instead.
func Anonymize ¶
Anonymize replaces sensitive tokens in sql -- identifiers, strings, numbers -- with fixed-width, length-preserving, consistent aliases (the same alias for every occurrence of the same original text), and blanks comment bodies and hint bodies, matching the reference's own sqlglot.anonymize.anonymize + render run together. The result is always the same LENGTH as sql: every alias is fitted back into the exact span its original token held, and the gaps between tokens keep their whitespace and comment markers with the comment BODY blanked.
Never fails: a statement the tokenizer cannot finish still comes back -- with a synthetic tail standing in for whatever it could not read -- since this exists to make SQL safe to log even when it is broken.
func CanonicalSQL ¶
CanonicalSQL is the definition written back from its tree, with the differences that do not change what a routine is taken out: comments, whitespace, keyword case and brackets round a name that reads the same without them all vanish; CREATE OR ALTER becomes CREATE, PROC becomes PROCEDURE, and a parameter's OUT becomes OUTPUT. String literals are kept exactly as written. A definition that does not parse is an error -- there is no textual fallback.
func Dialects ¶
func Dialects() []string
Dialects lists the dialects the port configures, neutral first, the rest alphabetically -- every key dialectConfigs actually has, not a fixed list from when there were five of them, which silently stopped growing while the dialects landing here kept going.
func Format ¶
Format lays a statement out one clause per line, with subqueries indented.
It works on tokens rather than on a parse, so a fragment the parser refuses still formats. It only ever moves whitespace: every token keeps the text it was written with, keyword case included, and comments stay where they stood. A statement the tokenizer cannot lex is an error.
func FormatScript ¶ added in v1.0.4
FormatScript keeps existing line boundaries while formatting clauses.
func FunctionName ¶
func FunctionName(e *Expression, dialect string) (string, bool)
FunctionName is the name a function node is written with in a dialect, and whether the node is a function at all.
It exists for the layer above: a guard denying OPENROWSET or xp_cmdshell has to ask what a node is called, and the answer is not on the node -- a Count does not remember that it was written COUNT, and in T-SQL with big_int set it is written COUNT_BIG.
func Generate ¶
func Generate(e *Expression, dialect string) (string, error)
Generate renders a tree as SQL in a dialect.
func IsIntegerType ¶
func IsIntegerType(t *Expression) bool
IsIntegerType reports whether a stamped type is one the reference counts as an integer -- which is what decides whether a subscript's index is shifted.
func IsWrite ¶
func IsWrite(e *Expression) bool
IsWrite reports whether a parsed statement changes anything.
The guard above this port used to learn that from ErrNotAQuery, which said "this is a write" only because a write could not be READ. Now that they can be read, the fact has to be asked for, and a caller that keeps using the error will see a CREATE go past as though it were a query.
The class of the root is not enough. SELECT … INTO is still a Select, and a write can sit under a UNION, a CTE or a DESCRIBE. Walking is the same answer the first consumer already has to give; asking only the root lets those through. INTO on a Pivot or Unpivot names a column, not a table, so only a Select's into -- and a Show's into_outfile -- count as a write slot.
func SplitBatches ¶
SplitBatches splits a script into its batches at each GO that stands alone on its line, as sqlcmd and SSMS do. A GO inside a string or a comment is text, not a separator, because the script is tokenized rather than scanned by line. Batches holding nothing but whitespace and comments are dropped.
`GO <count>`, which runs the batch before it that many times, is refused: a definition run twice is not a definition. So is anything else after GO on its line.
Types ¶
type BooleanSQL ¶
type BooleanSQL struct {
TrueValue string
FalseValue string
TrueCondition string
FalseCondition string
}
ClassTrigger names the classes that, at Index, make a builder produce something other than what the probe recorded. SyntaxTemplate is how one shape of a syntax function is written, with {key} where each argument goes. BooleanSQL is how a boolean is written in each position.
type ClassTrigger ¶
type CompositeTypeSQL ¶
type CompositeTypeSQL struct {
ArrayTemplate string
ArraySizedTemplate string
StructOpen string
StructClose string
StructFieldSep string
// MapTemplate is set only where MAP does NOT reuse the struct
// delimiters -- Materialize's own `MAP[key => value]` -- and is
// empty everywhere else, where MAP falls through to StructOpen/
// StructClose like every other nested type.
MapTemplate string
}
CompositeTypeSQL is how a type that contains another type is written. The array form is a TEMPLATE rather than a pair of delimiters because it is not the same shape everywhere: DuckDB suffixes (`INT[]`) and Databricks wraps (`ARRAY<INT>`).
type Config ¶
type Config struct {
Name string
SingleTokens map[string]TokenType
Keywords map[string]TokenType
Quotes map[string]string
FormatStrings map[string]FormatString
Identifiers map[string]string
// Comments maps a start delimiter to its end. An empty end means the
// comment runs to end of line -- the reference stores None there.
Comments map[string]string
StringEscapes set
// StringEscapePreferred is STRING_ESCAPES[0] -- the reference's generator
// always escapes a quote with the FIRST listed escape, not whichever one
// a set's own iteration happens to visit first. Redshift reads both `\`
// and `'` as escapes but writes only `\`; StringEscapes alone cannot
// tell the two apart once order is gone, which is why this exists
// alongside it rather than replacing it.
StringEscapePreferred string
ByteStringEscapes set
IdentifierEscapes set
EscapeFollowChars set
Commands ttset
CommandPrefixTokens ttset
NestedComments bool
HintStart string
TokensPrecedingHint ttset
HasBitStrings bool
HasHexStrings bool
NumericLiterals map[string]string
VarSingleTokens set
StringEscapesAllowedInRawStrings bool
HeredocTagIsIdentifier bool
HeredocStringAlternative TokenType
NumbersCanBeUnderscoreSeparated bool
NumbersCanHaveDecimals bool
IdentifiersCanStartWithDigit bool
UnescapedSequences map[string]string
// Tables is the parser's vocabulary for this dialect.
Tables *ParserTables
// contains filtered or unexported fields
}
Config is one dialect's resolved tokenizer tables. The fields mirror the reference's TokenizerCore constructor one-for-one; dialects_gen.go fills them from the pinned reference so a dialect override cannot be missed by hand.
type DataTypeKind ¶
type DataTypeKind string
DataTypeKind is the reference's DataType.Type enum member, which dumps as its own record class rather than as a plain leaf.
type DataTypeSpec ¶
type DataTypeSpec struct {
Kind string // dialect-preserving kind: NVARCHAR, DECIMAL, UUID, REAL, NTEXT, ...
Name string // as the dialect writes it: NUMERIC for DECIMAL, UNIQUEIDENTIFIER for UUID
Max bool // (MAX)
// Length is a string or binary type's size; Precision and Scale a
// number's, and Scale alone a time's fractional seconds -- DATETIME2(7).
Length, Precision, Scale *int
}
DataTypeSpec is a data type taken apart: its kind, and what its parameters say. A size the type was not written with is nil.
func DataTypeSpecOf ¶
func DataTypeSpecOf(e *Expression, dialect string) (DataTypeSpec, error)
DataTypeSpecOf takes a DataType node apart, naming it as the dialect writes it.
func (DataTypeSpec) String ¶
func (s DataTypeSpec) String() string
type DiffEdit ¶
type DiffEdit struct {
Kind EditKind
Expression *Expression
Source *Expression
Target *Expression
}
DiffEdit is one entry in an edit script -- the reference's Insert, Remove, Move, Update and Keep dataclasses collapsed into one shape. Insert and Remove carry only Expression; Move, Update and Keep carry Source and Target, the two ends of what got matched.
func Diff ¶
func Diff(source, target *Expression, dialect string, deltaOnly bool) []DiffEdit
Diff returns the edit script that turns source into target: the reference's own `sqlglot.diff.diff`, the Change Distiller algorithm (Fluri & Pinzger, building on Chawathe et al.) run over two already-parsed trees. Both trees are copied first, so the ones passed in are never mutated.
deltaOnly excludes Keep edits, which is what the reference's own tests hold the algorithm to -- and what a caller comparing two versions of a query actually wants: everything that agreed contributes nothing to read.
type Expression ¶
type Expression struct {
// Class is the reference's node class name, e.g. "Select", "Table",
// "Identifier". Kept as the Python spelling so dumps compare directly.
Class string
// Args are the node's named children and leaf values, in the reference's
// key names ("this", "expressions", "from_", "db", "quoted", …). Keys
// records insertion order, because the reference's dump order depends on
// it and so the comparison does too.
Args map[string]any
Keys []string
// Type is the node's type annotation. Most nodes have none, but a cast
// carries the type it casts to, and the reference dumps it as its own
// nested record list under "t" -- so a port that ignored it would mismatch
// on every cast.
Type *Expression
// Parent is set by the parser; never serialised.
Parent *Expression
// Meta is the reference's `meta`: facts about how a node was WRITTEN
// rather than what it is -- "name", the spelling a function was read
// with, in a dialect that writes it back that way. The dump's "m" is
// metadata and not compared, so this never affects tree equality.
Meta map[string]any
// contains filtered or unexported fields
}
Expression is one node of a parsed statement.
It mirrors sqlglot's Expression closely enough that a tree dumped by the Python reference and a tree built here can be compared field by field: a class name, and named args each holding a child, a list of children, or a leaf value. That comparability is the whole verification strategy, so the shape is not negotiable -- where this port disagrees with the reference, the port is wrong until shown otherwise.
func Annotate ¶
func Annotate(e *Expression, dialect string) *Expression
Annotate answers what TYPE an expression has.
This is the reference's `annotate_types`, and it is what several of the port's refusals are actually waiting on: whether a subscript's index is an integer, whether a connector's operand is already a condition, whether REGEXP_REPLACE's last argument is text. Each of those is a question about a type, and the port has been refusing rather than guessing.
SCOPE-FREE only. The reference resolves a column through the optimizer's scope machinery to a table to a schema; none of that is ported, so a column annotates as UNKNOWN here rather than being guessed at. That is not a crippling limit for the callers above -- a literal, a cast and an operator over them all have local answers, which is most of what the refusals need.
A nil result means "no answer", which callers must treat as UNKNOWN rather than as any particular type.
func ApplyIndexOffset ¶
func ApplyIndexOffset(this *Expression, items []*Expression, offset int, dialect string) ([]*Expression, bool)
ApplyIndexOffset shifts a subscript between the dialect's numbering and sqlglot's 0-based Bracket. The PARSER subtracts the offset and the GENERATOR adds it back, which is why both call this.
Almost all of it is conditions rather than arithmetic: it fires only for a single index, only where the base is UNKNOWN or an ARRAY, and only where the index is an INTEGER. So `a[x]`, `a['k']` and `a[1:2]` keep the index they were written with, and gain only the type annotations the reference stamps on them while deciding not to shift.
It reports false where the port cannot type the subtree. Its annotator is narrower than the reference's, and stamping UNKNOWN where the reference infers a type would record the port's own ignorance as an answer.
func New ¶
func New(class string, args ...Arg) *Expression
New builds a node and wires its children's Parent pointers.
Arguments are variadic pairs rather than a map because the reference's dump order follows arg declaration order, and Go map iteration is randomised -- a map here would make the dump differ run to run and the differential comparison flap.
func ParseDataType ¶
func ParseDataType(s, dialect string) (*Expression, error)
ParseDataType reads a bare data type -- `nvarchar(max)`, `decimal(18,2)` -- as a column definition would. Anything after the type is an error.
func ParseJSONPath ¶
func ParseJSONPath(path string) (*Expression, error)
ParseJSONPath parses a bare JSONPath selector the way the reference's `sqlglot.jsonpath.parse` does for its own base dialect: no dialect-specific tokenizer override, so `-` is never a var character.
func ParseOne ¶
func ParseOne(sql, dialect string) (*Expression, error)
ParseOne parses a single statement in a dialect and returns its tree.
func Simplify ¶
func Simplify(e *Expression, dialect string) *Expression
Simplify rewrites a tree the way the reference's optimizer does.
This is the first thing in the port that CHANGES a tree rather than reproducing one. That distinction is the reason the execution oracle exists: every other harness here compares the port against sqlglot, which cannot tell a wrong-but-plausible rewrite from a right one -- the SQL still parses, still round-trips, and still runs. It just returns different rows.
The rule is conservative throughout: where a rule's precondition cannot be established, the node is LEFT ALONE. A rewrite the port declines to make shows up as a statement it did not simplify far enough, which the gate counts and which costs nothing. A rewrite it makes wrongly is a different question asked of the database.
The reference runs `annotate_types` before simplifying and several of its rules decide on the types that pass leaves behind. Those rules are not here yet, and the nodes they would touch are left alone rather than guessed at.
func (*Expression) Append ¶
func (e *Expression) Append(key string, child *Expression)
Append adds one child to a list-valued arg, creating it if absent -- the reference's `append`. The key takes its position on first use, which is what puts joins immediately after from_ in the dump.
func (*Expression) Copy ¶
func (e *Expression) Copy() *Expression
Copy returns a deep copy of the node.
Simplify rewrites trees, and rewriting one in place would mutate the tree the differential holds -- the parser's output is compared against the reference before and after. So a rewrite builds a new tree and the original is left as it was parsed.
func (*Expression) Dump ¶
func (e *Expression) Dump() []map[string]any
Dump renders the tree in the reference's `serde.dump()` format, so a Go tree and a Python tree compare as the SAME kind of value.
The format is a flat list of records in pre-order. Each record carries the node's class ("c"), the index of its parent ("i"), the arg key it sits under ("k"), and "a": true when it is one element of a list. A LEAF value is its own record with "v" -- not a field on its parent. Order follows the reference's iterative algorithm exactly: children are pushed onto a stack in reverse so they pop in declaration order, which means arg order is part of the contract and Args is kept as an ordered sequence rather than a map.
Two reference fields are deliberately not produced: "m" (source positions) and "o" (comments). They are metadata, not structure, and the comparison in the harness strips them from the reference before diffing.
func (*Expression) DumpJSON ¶
func (e *Expression) DumpJSON() []byte
DumpJSON is Dump as bytes, for a test's diff output.
func (*Expression) Equal ¶
func (e *Expression) Equal(other *Expression) bool
Equal reports whether two nodes are the same tree.
It compares what the DUMP compares -- class, arg keys in order, and values -- because that is what the reference is held to. Parent pointers are excluded; they describe where a node sits, not what it is.
func (*Expression) FindAll ¶
func (e *Expression) FindAll(classes ...string) []*Expression
FindAll returns every descendant (including the node itself) whose Class is one of those named -- the reference's `find_all`.
func (*Expression) Name ¶
func (e *Expression) Name() string
Name is the reference's `.name`: the string of `this` when it is an Identifier or literal, else "".
func (*Expression) Set ¶
func (e *Expression) Set(key string, value any)
Set assigns one arg, adopting any child expressions.
A typed nil child is normalised to an absent one. The reference stores None there, and an absent arg produces no dump record at all -- so a *Expression that happens to be nil must not become a leaf record holding "null", which is what a naive store would do and what the differential would then report as a mismatch on every optional clause.
func (*Expression) This ¶
func (e *Expression) This() *Expression
This is the conventional primary child, as in the reference.
func (*Expression) Walk ¶
func (e *Expression) Walk(fn func(*Expression) bool)
Walk visits the node and every descendant, depth first, in arg-key order so traversal is deterministic. The type annotation is visited too, when it is not already a child: a cast stores the same DataType in Args["to"] and Type, but a builder can stamp Type alone, and FindAll("DataType") has to see that. The reference's walk does not; this one does because a guard looking for types would otherwise miss them. Returning false from fn stops descent into that node's children.
type FormatString ¶
FormatString is a prefixed string literal -- x'…', b'…', $$…$$ -- carrying the delimiter that closes it and the token type it produces.
type FuncArg ¶
type FuncArg struct {
Key string
Index int
VarLen bool
Const any
// Wrap names a class to build FROM the argument rather than to hold
// it: DATEADD records unit=Var(args[Index].name upper-cased), and the
// argument itself appears nowhere in the result. 28 names do this,
// and every one of them used to be refused outright.
Wrap string
// WrapArgs are the wrapper’s other arguments -- a Literal always
// carries is_string, and a check for exactly one argument rejected
// every builder whose wrapper was a Literal rather than a Var.
WrapArgs []FuncConst
// Nested names a class built AROUND the arguments rather than
// from one of them -- DuckDB's ANY_VALUE is an IgnoreNulls over
// an AnyValue, and T-SQL's YEAR a Year over a TsOrDsToDate. Its
// own arguments are described the same way, one level down.
Nested string
NestedArgs []FuncArg
// NestedExcept names the argument KINDS that ESCAPE that wrapper:
// "string", "number", "cast", "call", "subquery". T-SQL's LEN casts
// its argument to TEXT unless it is ALREADY a string, so the cast
// belongs in the spec and a string literal is the exception. Every
// wrapper used to be unconditional, and a builder with a rule like
// this one was refused as undescribable at every arity.
NestedExcept []string
// NestedAnnot is the TYPE the wrapper is annotated with, where the
// builder annotates as well as builds: `exp.cast` records its target
// on the node too, and the reference dumps that. A port that built
// the cast without it produced a tree the differential called
// different over a field no SQL shows.
NestedAnnot *FuncArg
}
type FuncConst ¶
FuncConst is an argument that must hold this value for the spelling beside it to apply.
type FuncSQL ¶
type FuncSQL struct {
Name string
Keys []string
Consts []FuncConst
NoParens bool
// MinArgs is how many members a LIST argument must hold for this
// spelling to apply. T-SQL writes CONCAT(a, b) for two and just `a`
// for one, so the call form belongs to the wider counts alone.
MinArgs int
}
FuncArg fills one key: a positional argument, a variadic tail that collects everything from Index onward, or a constant the builder always sets -- COUNT is always big_int, whatever it was called with. FuncSQL is one way a function node may be written: the keyword, the argument keys that become its arguments in order, and the constant arguments that select this spelling over another. T-SQL writes a Count as COUNT_BIG when big_int is set and COUNT when it is not.
type GenerateError ¶
type GenerateError struct{ What string }
GenerateError names what the generator could not write.
What is vocabulary -- a node class, a clause, a dialect limitation -- never a caller's identifier. Error() is safe to log; a caller that needs the name without scraping the message reads the field.
func (*GenerateError) Error ¶
func (e *GenerateError) Error() string
func (*GenerateError) Is ¶
func (e *GenerateError) Is(target error) bool
Is makes errors.Is(err, ErrGenerate) hold for this error too.
type JSONPathFunc ¶
type JSONPathFunc struct {
Class string
// Fold folds every argument after the first into ONE path, a segment
// each -- JSON_EXTRACT_PATH(x, 'y', '0', 'z'). Otherwise a single
// argument is read as a path STRING.
Fold bool
Consts []FuncConst
// KeepsTail says whether arguments past the path survive. Databricks
// DROPS them, and dropping an argument changes what the call means, so
// the port refuses rather than writing a call that says something else.
KeepsTail bool
// IntSubscripts: a folded key that reads as an integer is a SUBSCRIPT
// rather than a key of that name, shifted by IndexShift.
IntSubscripts bool
IndexShift int
// RootDefault: with no path argument the whole document is meant, and
// the builder supplies a bare root. T-SQL's JSON_QUERY(x) does this.
RootDefault bool
}
JSONPathFunc describes a name that turns its arguments into a JSON path.
Nine names across these dialects do it, and the generic probe rejected every one: it feeds placeholder COLUMNS, and these builders look at what they were handed, so the shape they show it is not the shape real SQL takes.
type JSONPathSQL ¶
type JSONPathSQL struct {
// Form is the call around the path, for an override -- measured with
// the same rendering as the separators so the two agree on who
// writes the dot after the root.
Form string
// PlainForm is that same call with an operand that is NOT a path,
// which the path form would have quoted into something else.
PlainForm string
Open string
Close string
Key string
// KeyAfter is the form for a key that is not the FIRST: Databricks
// writes `c1:item.price`, a colon and then a dot.
KeyAfter string
// EscapesQuote says a quote inside a key is doubled, which it must
// be where the path is written inside a string and must NOT be
// where the form is bare SQL.
EscapesQuote bool
Subscript string
QuotedKey string
}
JSONPathSQL is the text around each piece of a JSON path.
type JSONPerPart ¶
type KindSpec ¶
ValueDispatch is one name's choice of class by the WORD in an argument: HASHBYTES('SHA1', x) is an SHA, HASHBYTES('MD5', x) an MD5, and anything else the Default. The words are read off the reference builder's own constants, not transcribed. KindSpec is the shape one arity takes when the argument at Index is of a particular KIND. PostgreSQL's REGEXP_REPLACE reads its last argument as flags when it is a string that does not spell a number, and as a position when it does -- one arity, two shapes.
type NotAQueryError ¶
type NotAQueryError struct{ Kind string }
NotAQueryError names the statement. The guard above reports "DROP is not allowed; this endpoint is read-only", so it needs the word, not just the fact -- and reading it back out of a message would be a parser of its own.
func (*NotAQueryError) Error ¶
func (e *NotAQueryError) Error() string
func (*NotAQueryError) Is ¶
func (e *NotAQueryError) Is(target error) bool
Is makes errors.Is(err, ErrNotAQuery) hold for this error too.
type Param ¶
type Param struct {
Name string // with its @
Type *Expression
Default *Expression
Output bool // OUTPUT or OUT
ReadOnly bool // a READONLY table-valued parameter
}
Param is one parameter of a routine.
type ParseDiagnostic ¶ added in v1.0.4
type ParserTables ¶
type ParserTables struct {
// IDVarTokens are keywords that may be used as an identifier.
IDVarTokens map[TokenType]struct{}
// TableAliasTokens are keywords that may be used as a table alias --
// a strict subset: a keyword that can start a clause is excluded, or an
// implicit alias would swallow it.
TableAliasTokens map[TokenType]struct{}
// NamedFunctions are function names the reference parses into a node
// class of their own. Everything else with an argument list is an
// Anonymous call, which is the only form this port builds so far -- a
// name in here is refused rather than flattened into Anonymous.
NamedFunctions map[string]struct{}
// NoParenFunctions are names that are a function call without an
// argument list at all, e.g. CURRENT_DATE.
NoParenFunctions map[TokenType]struct{}
// NoParenFunctionClasses is the node each of those builds, with no
// arguments at all.
NoParenFunctionClasses map[TokenType]string
// Functions is what each named function builds, worked out by running
// the reference's own builder. A name in NamedFunctions but absent here
// builds something no fixed mapping describes, and is refused rather
// than approximated.
Functions map[string]FuncSpec
// FunctionSQL is how the generator writes each of those nodes back
// out. A node absent here is one the reference writes in some shape
// other than NAME(a, b); the generator refuses it rather than
// emitting something that would parse back differently.
FunctionSQL map[string][]FuncSQL
// KeepsFunctionCase: a call is written in the case it was read in,
// not upper-cased -- ClickHouse's function names are case-sensitive.
// KeepsOriginalName names the classes written under the name they
// were read with (`count()` stays `count()`), rather than their own.
KeepsFunctionCase bool
KeepsOriginalName map[string]struct{}
// AggFunctions and AggFunctionSuffixes are ClickHouse's aggregate
// names and the combinator suffixes that may follow them, longest
// first: `sumIfMerge` is sum with If and Merge, and an aggregate node.
// SetOpDistinctByDefault is what a bare UNION, EXCEPT or INTERSECT
// means: "DISTINCT", "ALL", or "" where the dialect requires one
// of the two words (ClickHouse's UNION). The word that matches the
// default is not written back.
SetOpDistinctByDefault map[string]string
AggFunctions map[string]struct{}
AggFunctionSuffixes []string
// StandaloneUniqueBefore holds the words before which UNIQUE is a
// whole constraint on its own (SQLite's `UNIQUE REFERENCES t`).
StandaloneUniqueBefore map[string]struct{}
// BinarySQL and UnarySQL are how each operator node is written.
// DuckDB writes Pow as ** where the default writes POWER(a, b), so
// the spelling is read from the reference's generator, not assumed.
BinarySQL map[string]string
UnarySQL map[string]string
// LimitIsTop puts the row ceiling in front of the projections, as
// T-SQL's TOP does, rather than after the query as LIMIT does. The
// guard rewrites one node either way; the dialect decides where it
// lands, which is the whole reason the rewrite works at all.
// TypeSQL is how each data type is written in this dialect: T-SQL
// spells DataType.Type.INT as INTEGER.
TypeSQL map[string]string
// SizedTypeSQL is the name a type takes when it carries PARAMETERS,
// where that differs: Databricks writes a bare VARCHAR as STRING and
// a VARCHAR(255) as itself.
SizedTypeSQL map[string]string
// NullableTemplate wraps a type whose node does not say it is
// non-nullable -- ClickHouse writes a type read from another
// dialect as `Nullable(T)`, {type} where T goes -- and is empty
// wherever nullability is not part of a type's spelling.
// NeverNullableTypes are the kinds it never wraps: composites, and
// the geometry types ClickHouse cannot make nullable.
NullableTemplate string
NeverNullableTypes map[string]struct{}
// IdentifierStart and IdentifierEnd are the delimiters a quoted name
// is written with: brackets in T-SQL, backticks in Databricks.
IdentifierStart string
IdentifierEnd string
// QualifiesDerivedOutputs names every unnamed column of a CTE or a
// derived table on the way out, because T-SQL will not accept one
// without a name. Two executors that disagreed here would send the
// engine different SQL for the same question.
QualifiesDerivedOutputs bool
// CoercesBooleans marks a dialect with no boolean type, where a value
// used as a condition is written `x <> 0`. The port does not perform
// that rewrite; it refuses, because emitting the uncoerced form would
// be a statement the engine rejects.
CoercesBooleans bool
LimitIsTop bool
// LimitOnlyLiterals folds a LIMIT/OFFSET that is not already a
// plain literal down to one at generation time -- `LIMIT 1 + 1`
// writes as `LIMIT 2` -- because this dialect's engine will not
// accept an expression there at all.
LimitOnlyLiterals bool
// MultiArgDistinct says this dialect writes `DISTINCT a, b` as
// itself; where this is false, it has no multi-column DISTINCT
// and the call is rewritten into a CASE that returns NULL if any
// argument is NULL and the arguments as a row otherwise.
MultiArgDistinct bool
// IntervalAllowsPluralForm says an interval unit is written
// whichever way it was: PLURAL where the statement said `DAYS`.
// Where this is false, the unit is always singularised on the
// way out, through the reference's own fixed TIME_PART_SINGULARS
// table -- a reference-level constant no dialect overrides, so
// it is written out once in the port rather than harvested here.
IntervalAllowsPluralForm bool
// LimitFetch says which of LIMIT and FETCH this dialect writes: the
// port parses either into the class it was written as, and this
// dialect converts one into the other at generation time ("ALL"
// writes each node class as itself, converting neither).
LimitFetch string
// ConcatAsDPipe says this dialect ALWAYS writes CONCAT(a, b, ...)
// as a `||` chain instead -- Redshift's own choice, unconditional
// (it does not depend on the tree's own `coalesce` flag the way
// other CONCAT_COALESCE dialects' generic rendering does).
ConcatAsDPipe bool
// SupportsSingleArgConcat says a one-argument CONCAT(a) call is
// written as itself; where this is false, the call is written
// bare -- `a`, not `CONCAT(a)`.
SupportsSingleArgConcat bool
// SuppressedWriteClasses names node classes this dialect writes as
// nothing at all -- Materialize drops AUTO_INCREMENT, GENERATED AS
// IDENTITY, PRIMARY KEY and ON CONFLICT entirely, none of which it
// supports -- probed by building a bare instance of each candidate
// class and checking the reference actually renders it empty.
SuppressedWriteClasses map[string]struct{}
// RewritesSerialToIdentity says SERIAL/SMALLSERIAL/BIGSERIAL write
// back as the base int type plus GENERATED AS IDENTITY and NOT
// NULL, matching how the reference's own Postgres-family write
// path expands it -- a dialect that also suppresses
// GeneratedAsIdentityColumnConstraint (see SuppressedWriteClasses)
// is left with just the NOT NULL, which is correct for it.
RewritesSerialToIdentity bool
// TzToWithTimeZone says this dialect writes TIMETZ/TIMESTAMPTZ as
// their bare-name equivalent (TIME/TIMESTAMP) plus a trailing
// ` WITH TIME ZONE`, appended after any size the type carries
// rather than baked into a name of its own.
TzToWithTimeZone bool
// EliminatesDistinctOn says this dialect has no `DISTINCT ON` of its
// own and rewrites the whole SELECT into a `ROW_NUMBER()`-windowed
// subquery instead, the way the reference's own preprocessing does.
EliminatesDistinctOn bool
// StatementTokens begin a statement that is not a query -- CREATE,
// DELETE, INSERT and the rest. Anything else at the top level is
// parsed as a bare expression, which is what the reference does and
// what most of its own fixture corpus consists of.
StatementTokens map[TokenType]struct{}
// FuncTokens are the tokens allowed to name a function call.
FuncTokens map[TokenType]struct{}
// NoParenFunctionNames are names that are a call with no argument
// list -- CURDATE in Databricks, CASE and IF everywhere -- and so are
// not available as a bare column name.
NoParenFunctionNames map[string]struct{}
// InvalidFuncNameTokens are the token types that never name a
// call, however the name reads: a QUOTED identifier or a string
// is a name and nothing else, so a quoted CASE is a column even
// though the bare word opens one.
InvalidFuncNameTokens map[TokenType]struct{}
// ValuesFollowedByParen says a bare VALUES -- one with no argument
// list after it -- is a column name in this dialect rather than
// the start of a VALUES clause.
ValuesFollowedByParen bool
// BareNameIsColumn holds the no-paren function names that read as
// a COLUMN when nothing usable follows them. Probed one name at a
// time: NEXT retreats without its `VALUE FOR` and CURDATE does not
// retreat at all.
BareNameIsColumn map[string]struct{}
// ColonLambdaRead says the dialect reads `LAMBDA a, b : body`, and
// ColonLambdaWrite is the template it writes one back with -- empty
// where the dialect has no spelling of its own and the ordinary
// arrow form is used instead.
ColonLambdaRead bool
ColonLambdaWrite string
// FunctionsWithAliasedArgs are the calls whose arguments may name
// themselves even though the call itself is one the port builds a
// node for: `STRUCT(1 AS a)` is a Struct of one named field.
FunctionsWithAliasedArgs map[string]struct{}
// StructTemplate wraps a struct's fields and StructFieldTemplate
// writes one named field. `{key}` is the field name written as an
// identifier and `{name}` is the bare name, which the dialect that
// quotes its keys as strings uses instead.
StructTemplate string
StructFieldTemplate string
// PropertySpecs are the words a CREATE may say about the thing it
// makes, keyed by the word. Class is the node built and Shape is
// what follows the word; both are probed by parsing one, because
// the reference keeps a little grammar per name and none of it is
// readable as data.
PropertySpecs map[string]PropertySpec
// PropertyLocation says WHERE each property class is written --
// POST_SCHEMA ones stand on their own after the columns, POST_WITH
// ones go together inside one wrapped list.
PropertyLocation map[string]string
// WithPropertiesPrefix opens that wrapped list: WITH everywhere but
// Databricks, which writes TBLPROPERTIES.
WithPropertiesPrefix string
// PropertyNameQuoted says a plain key-and-value property writes its
// KEY in quotes -- Databricks writes `'a.b'=15` for what the others
// write `a.b=15`. Read off a rendered node.
PropertyNameQuoted bool
// StringArgWraps are the positions where a builder REWRITES a
// string argument rather than carrying it: T-SQL's DATETRUNC casts
// one to DATETIME2, PostgreSQL's GENERATE_SERIES turns a step of
// `'1 day'` into an INTERVAL. The port does the rewrite itself
// before building, so a string that only moves in this way is not
// evidence of a builder nobody can describe.
StringArgWraps map[string]map[int]string
// CallNamesTheReferenceKnows are every name the reference reads as
// something other than an anonymous call -- a builder, a parser of
// its own, a no-paren form, or a quantifier over a subquery. A name
// NOT here is one the reference reads anonymously too, which is what
// lets the annotator answer UNKNOWN for it without hiding a parse
// gap behind the answer.
CallNamesTheReferenceKnows map[string]struct{}
// BareProcedureWrapper is the class a CREATE PROCEDURE's name is
// wrapped in when it was written WITHOUT a parameter list. T-SQL
// puts a StoredProcedure round it and the rest leave the name
// alone, so the empty string means no wrapper.
BareProcedureWrapper string
// ProcedureWithOptions are the words a CREATE PROCEDURE may say
// after WITH, and the class each becomes. The reference reads two
// of them as a view attribute and the rest as a procedure option,
// which is a distinction nothing in the words themselves makes --
// so each is asked by parsing one.
ProcedureWithOptions map[string]string
// ColumnDefaultAfterEquals says a column definition may be followed
// by `= <value>`, which becomes its default. T-SQL alone reads it,
// and it is how a procedure parameter is given one.
ColumnDefaultAfterEquals bool
// IfIsAStatement says a bare IF opens a STATEMENT in this dialect --
// `IF <cond> BEGIN ... END` -- rather than being a call or a name.
IfIsAStatement bool
// AlterCollateIsVar says the name a COLLATE gives is kept as a Var
// rather than as an Identifier, and AlterColumnTypeTakesNull that a
// retyped column may say NOT NULL or NULL after its new type.
AlterCollateIsVar bool
AlterColumnTypeTakesNull bool
// AlterColumnNullabilityWritten says a retyped column's NOT NULL is
// written back. Where it is not, the reference drops the words and
// this port refuses rather than writing a column that takes nulls
// when the statement said it must not.
AlterColumnNullabilityWritten bool
// OpclassFollowWords and OpclassFollowTokens are what may follow an
// indexed column WITHOUT being an operator class for it: a word
// that orders the column, or the punctuation that ends it.
OpclassFollowWords map[string]struct{}
OpclassFollowTokens map[TokenType]struct{}
// TrimTypes are the words that may say WHERE a TRIM trims, and
// TrimPatternFirst that its comma form writes the characters to
// trim before the string they are trimmed from.
TrimTypes map[string]struct{}
TrimPatternFirst bool
// ProjectionEqualsIsAlias reads `SELECT a = 1` as `1 AS a` rather
// than as a comparison. Only T-SQL does, and it is the same text
// meaning two different things, so nothing but the dialect settles it.
ProjectionEqualsIsAlias bool
// PositionalColumns reads `#2` as the SECOND output column rather
// than as anything to do with a hash.
PositionalColumns bool
// TypedDivision and SafeDivision are recorded on every Div node; the
// reference reads them off the dialect, so they are not always false.
TypedDivision bool
SafeDivision bool
// DPipeIsStringConcat decides whether || concatenates or is a logical
// or; StrictStringConcat becomes the DPipe node's safe flag, inverted.
DPipeIsStringConcat bool
StrictStringConcat bool
// JoinsHaveEqualPrecedence makes a comma join an explicit CROSS join.
JoinsHaveEqualPrecedence bool
// BareJoinIsOnTrue: a JOIN written with no ON. Databricks records it
// as `ON TRUE` explicitly; every other dialect leaves the slot empty
// and writes the comma form. Same relation either way, different
// tree and different SQL -- so the two executors would send the
// engine different statements. PROBED, like the rest.
BareJoinIsOnTrue bool
// DefaultTypeParams are the parameters a BARE type gains in this
// dialect. DuckDB reads `numeric` as DECIMAL(18, 3) at parse time --
// sqlglot calls these TYPE_CONVERTERS -- so a port that left the type
// unparameterised sent a different CAST to the engine than the Python
// executor did, and on a division that is a different NUMBER.
// PROBED: the converters are closures, so the constants cannot be
// read out; they are recovered by parsing a bare type and looking.
DefaultTypeParams map[string][]string
// IsNotNullWrapsInNot says how `x IS NOT NULL` is SHAPED. Every
// dialect but PostgreSQL builds Not(Is(x, NULL)) and writes it back
// as `NOT x IS NULL`; PostgreSQL records the negation on the Is
// node instead. PROBED, not transcribed -- sqlglot has no flag for
// it, the rule lives in a dialect override, and a port that assumed
// one shape diverged on one of the commonest predicates in SQL.
// DropsTypeParams are types whose PARAMETERS this dialect discards.
// The mirror of DefaultTypeParams, out of the same TYPE_CONVERTERS:
// DuckDB reads every text type as TEXT and drops the length, so
// `VARCHAR(5)` is a bare TEXT and a port that kept the 5 sent the
// engine a different CAST. PROBED, for the same reason.
DropsTypeParams map[string]bool
// LimitAllMeansNoLimit: `LIMIT ALL` is PostgreSQL for "no limit",
// and DuckDB and Databricks follow. T-SQL and the neutral dialect
// read ALL as a column of that name instead. PROBED: the difference
// lands on the one clause the guard rewrites.
LimitAllMeansNoLimit bool
// StringSensitiveArgs are argument positions where a STRING
// LITERAL makes the reference build something structurally
// different: PostgreSQL reads a string step to GENERATE_SERIES as
// an Interval, and a trailing string to REGEXP_REPLACE as
// `modifiers`, shifting the arguments after it. The function probe
// uses placeholder COLUMNS, so neither rule fires and the recorded
// signature is right for columns and wrong for strings. A call that
// puts a string in one of these slots is REFUSED: the port cannot
// tell which slot was meant, and a plausible tree is the one thing
// it must not build. PROBED.
// CastSensitiveArgs are argument positions where an explicitly
// CAST argument changes how the CALL itself is written: DuckDB
// wraps BIT_OR over a non-integer in a round-and-cast, PostgreSQL
// casts a double before a two-argument ROUND. The tree is the same
// either way -- only the SQL differs -- so this is probed by
// RENDERING, and a call that would need it is refused rather than
// written without the coercion the engine needs. PROBED.
// ClassSensitiveArgs are argument positions where the CLASS of the
// argument itself changes what the builder makes: LOWER(HEX(x)) is a
// LowerHex, LOWER(x) is a Lower. A spec probed with a placeholder
// column describes only the second, so the call is refused when the
// argument is one of the listed classes. PROBED against every class
// this catalogue can itself produce.
// FunctionsByArity holds names whose shape depends on HOW MANY
// arguments the call has -- DATEDIFF of two is not DATEDIFF of
// three. One spec cannot describe those, so each count gets its
// own, and a count with no entry is refused.
// UnitAliases are the unit spellings a name normalises: T-SQL
// records DATEADD(qq, ...) as QUARTER, not QQ. Read off the
// builder itself, since nothing outside it shows the mapping.
UnitAliases map[string]map[string]string
// SyntaxFunctions parse their arguments with their own grammar
// rather than as a comma-separated list. A name here that the
// port has not implemented is missing GRAMMAR, which is a
// different thing from a builder it cannot describe.
SyntaxFunctions map[string]struct{}
// TableFunctions are names that are NOT a Table in a FROM clause:
// `FROM UNNEST(x)` is an Unnest. The port has no node for these,
// and wrapping the call in a Table round-trips perfectly while
// being a different tree, so they are refused. PROBED.
TableFunctions map[string]struct{}
// SyntaxSQL is how each of those is WRITTEN, one template per set
// of present arguments, rendered from the reference.
SyntaxSQL map[string][]SyntaxTemplate
FunctionsByArity map[string]map[int]FuncSpec
ClassSensitiveArgs map[string][]ClassTrigger
// TimeMapping is the dialect’s time-format spelling, and
// TimeFormatArgs the argument positions it applies to. T-SQL
// writes yyyy-MM-dd where the reference stores %Y-%m-%d, and the
// builder rewrites the literal on the way in.
TimeMapping map[string]string
TimeFormatArgs map[string][]int
// InverseTimeMapping spells a stored format back out again, and
// FormatTimeMapping is the SEPARATE table a one-character format
// is read through. Only the dialects whose FORMAT is a builder
// that reads its argument have the second one, which is what
// tells the port that builder is installed.
// DatePartMapping normalises a date part's spelling: T-SQL records
// DATEPART(mm, x) as MONTH. A part the map does not name is kept
// exactly as it was written, case and all.
DatePartMapping map[string]string
InverseTimeMapping map[string]string
FormatTimeMapping map[string]string
// FullFormatTimeMapping is TimeMapping with a dialect's OWN full-word
// spellings layered over it -- T-SQL's DATENAME(mm, x) wants the full
// month name, not the two-digit one TimeMapping's "mm" gives FORMAT.
FullFormatTimeMapping map[string]string
CastSensitiveArgs map[string]map[int][]string
// CastCoercions is what the dialect wraps an argument in, per the
// type it is cast to: DuckDB rounds a float into a BIT_OR and casts a
// decimal without rounding. A wrapper of `{arg}` alone means the slot
// takes that type as it stands.
CastCoercions map[string]map[int]map[string]map[string]string
// CastIdempotentTypes are the slots whose coercion the dialect
// applies whatever it is given, so an argument already carrying that
// cast leaves nothing to add and the plain spelling is exact.
CastIdempotentTypes map[string]map[string][]string
// CastElidedAt names, per class and per key, the cast TARGETS the
// reference's generator does not write there. Its own parser puts them
// in -- T-SQL's LEN(x) is a Length over a cast to TEXT -- and its
// generator takes them straight back out, so a port faithful in one
// direction and not the other wrote LEN(CAST(x AS VARCHAR(MAX))).
CastElidedAt map[string]map[string][]string
// CastElidedOver names, per cast TARGET, the classes a cast to that
// type is never written around: PostgreSQL's DIV is a Cast to DECIMAL
// over an IntDiv, written as just DIV(4, 2).
CastElidedOver map[string][]string
// CastSensitiveTypes says WHICH cast targets move the rendering in
// each of those positions. A slot is not sensitive to casting as
// such: DuckDB wraps a non-text argument to UPPER in a cast to TEXT,
// and leaves one that is already TEXT alone.
CastSensitiveTypes map[string]map[int]map[string][]string
// DropsZeroArgs are the argument keys a literal ZERO simply
// DISAPPEARS from -- DuckDB writes REGEXP_EXTRACT(x, p) for a
// zero group. A rule to FOLLOW, unlike the two below, and kept
// apart from them because refusing it also turned away every
// other literal in the same slot.
DropsZeroArgs map[string]map[int][]string
// ZeroSensitiveArgs is the same idea for a NUMBER rather than a
// cast: DuckDB drops a zero group from REGEXP_EXTRACT entirely.
// Kept apart from the cast trigger, because a call that moves for
// one says nothing about the other.
ZeroSensitiveArgs map[string]map[int][]string
StringSensitiveArgs map[string][]int
// WritesBooleanLiteral: whether TRUE and FALSE are written as
// themselves. T-SQL has no boolean literal -- the reference
// rewrites them to 1 and 0, and to `1 = 1` in a condition. That is
// a transform, not a spelling, and it is not ported; writing TRUE
// anyway sent an engine SQL it rejects. PROBED.
// ReservedKeywords must be QUOTED when written as an identifier
// even though the caller wrote them bare. DuckDB reserves `all`, so
// `SELECT 1 AS all` is written `AS "all"`; bare it is a syntax
// error on the engine.
ReservedKeywords map[string]bool
// BracketIsRewritten: DuckDB and PostgreSQL shift a subscript to
// sqlglot’s 0-based Bracket, annotate it, and run the shift
// through the SIMPLIFIER. That is the optimizer, which is not
// ported, so where this is set the subscript is REFUSED rather
// than built plainly. PROBED.
// ArrayOpen and ArrayClose are the text around an array literal:
// `[`/`]` in DuckDB, `ARRAY[`/`]` in PostgreSQL, `ARRAY(`/`)`
// elsewhere. PROBED.
ArrayOpen string
ArrayClose string
// IntervalUnitInsideString: PostgreSQL writes INTERVAL ‘1 DAY’
// with the unit inside the quantity; everyone else writes
// INTERVAL ‘1’ DAY. PROBED.
IntervalUnitInsideString bool
// JSONArrowOnlyJSONTypes and JSONArrowScalarOnly are stamped on
// the node `->` and `->>` build. PROBED.
JSONArrowOnlyJSONTypes bool
// JSONArrowSetsScalarOnly says whether the arg is PRESENT on the
// node at all; PostgreSQL leaves it off and the others set false.
JSONArrowSetsScalarOnly bool
// JSONArrowTypesWithoutPath says whether only_json_types is still
// set when the operand is NOT a path -- PostgreSQL's builder
// returns before stamping it, DuckDB's stamps it regardless.
JSONArrowTypesWithoutPath bool
// JSONExtractNeedsParens lists the extraction classes this dialect
// writes as an OPERATOR, which the reference parenthesises when one
// is an operand: `(a -> b) & c`, but Databricks' `a:b & c` plain.
JSONExtractNeedsParens map[string]bool
// VariantExtractColon says `x:a` is a JSON extraction here, the
// form Databricks writes and this port used to write without ever
// being able to read one back.
VariantExtractColon bool
// JSONKeyValueSQL is one key/value pair inside JSON_OBJECT: DuckDB
// separates them with a comma and the others with a colon.
JSONKeyValueSQL string
// DefaultSampleMethod is the TABLESAMPLE method this dialect records
// when the statement names none. DuckDB says RESERVOIR either way.
DefaultSampleMethod string
// BareSampleCountIsPercent: `TABLESAMPLE (3)` is a PERCENTAGE in
// PostgreSQL and a number of rows everywhere else.
BareSampleCountIsPercent bool
// PrefixAlias: `SELECT foo: 1` NAMES the expression, DuckDB's
// spelling of `SELECT 1 AS foo`. The same characters are a JSON
// extraction in Databricks, so the dialect decides, not the shape.
PrefixAlias bool
// StringAliases: `SELECT 1 'foo'` names the column foo, the same
// as a bare word would -- the word just came already quoted. T-SQL
// has it; most dialects do not, and a bare string stays a value.
StringAliases bool
// NormalizeNotNull: `x NOTNULL` is written NOT x IS NULL here and
// kept as a negated IS elsewhere -- two trees for one word.
NormalizeNotNull bool
// StarExceptWord is what `* EXCEPT (a)` is written with: DuckDB
// says EXCLUDE, and both words are READ everywhere.
StarExceptWord string
// DeclareAssignment is what stands between a declared variable and
// its initial value.
DeclareAssignment string
// EndCommits: a bare END ENDS THE TRANSACTION here, and is a name
// or a block anywhere else.
EndCommits bool
// FormatSpellings says how each class that carries a FORMAT writes
// it: `inverse` through the dialect's own mapping -- the tree
// stores %Y-%m-%d and PostgreSQL writes YYYY-MM-DD -- `verbatim`
// as stored, and `other` through a table of its own, which the
// writer declines rather than guess at.
FormatSpellings map[string]string
// DefaultTimeFormat is the format a `default-dropped` class writes
// as nothing at all.
DefaultTimeFormat string
// LikeInsideSchema: a `LIKE other` that is NOT inside a column
// list brings its own parentheses here. SupportsCreateLike says
// the dialect writes the word at all.
LikeInsideSchema bool
SupportsCreateLike bool
// ExecuteBuildsExecute: EXEC names a procedure to run here, and is
// kept as raw text anywhere else.
ExecuteBuildsExecute bool
// ShowKinds are the phrases SHOW reads as a statement rather than
// keeping as text.
ShowKinds map[string]struct{}
// ReservedTokens are the ones that can never stand in for a name,
// which is what the reference asks where ANY token may.
ReservedTokens map[TokenType]struct{}
// SequenceOptions are the words a CREATE SEQUENCE takes that carry
// no value, each with the word that may follow it: NO CYCLE is one
// option, not two.
SequenceOptions map[string][]string
// CreatableTokens are the things a CREATE makes and a DROP
// removes, and CreatableKindNames what a dialect calls them where
// it uses another word.
CreatableTokens map[TokenType]struct{}
CreatableKindNames map[string]string
// How a COPY's parameters are written: separated by commas or by
// spaces, and with or without an = before each value. The names
// whose value is a LIST are kept apart, since those are read a
// different way again.
CopyIntoWritten bool
CopyParamsWrapped bool
CopyParamsAreCSV bool
CopyParamsNeedEQ bool
CopyVarlenOptions map[string]struct{}
// SupportsColumnJoinMarks says a bare column may carry Oracle-style
// `(+)` outer-join syntax -- Redshift's tokenizer maps that literal
// text to its own token, the same way the reference reads it as one.
SupportsColumnJoinMarks bool
// HasDistinctArrayConstructors says ARRAY[1, 2] and ARRAY(1, 2) are
// written back differently -- Redshift stamps the node with which
// bracket kind built it (bracket_notation) so generation can tell.
HasDistinctArrayConstructors bool
// SupportsImplicitUnnest says a comma- or CROSS-JOINed table whose
// name is DOTTED and whose first part names an earlier table in the
// FROM is really a nested column being iterated, not a real table --
// Redshift's `t, t.arr_col AS x` sugar for `t, UNNEST(t.arr_col) AS x`.
SupportsImplicitUnnest bool
// HasListConstructor says `LIST[1, 2]` builds a List rather than a
// column named LIST subscripted by [1, 2] -- true nearly
// everywhere `ARRAY_CONSTRUCTORS` maps the word, EXCEPT where the
// dialect reads it some other way first: DuckDB's own LIST type
// grammar intercepts it, and T-SQL's `[...]` already means a
// quoted identifier. Probed directly rather than read off the
// (unconditionally shared) table, since it is the OUTCOME that
// differs, not the table.
HasListConstructor bool
// DefaultsUnsizedCharTypes says a CREATE TABLE column typed bare
// VARCHAR or CHAR, with no length, is stamped with an implicit
// length of 1 -- Fabric's own reading of T-SQL's rule for what a
// missing length means (`learn.microsoft.com/.../char-and-varchar`).
DefaultsUnsizedCharTypes bool
// ZoneAwareTimestampConstructor says a TIMESTAMP/TIME typed
// literal carrying a zone offset or name reads as TIMESTAMPTZ/
// TIMETZ instead -- Presto's own reading of what the literal
// actually names, not the bare word that introduced it.
ZoneAwareTimestampConstructor bool
// UnaryOps is which token opens a PREFIX operator, and what it
// builds. The empty string is the no-op unary plus.
UnaryOps map[TokenType]string
// PrefixCalls is punctuation that NAMES a function written in
// front of its operand, keyed by the characters: DuckDB's `@x` is
// ABS(x), and it takes a whole arithmetic expression.
PrefixCalls map[string]string
// TsOrDsParents are the classes a TsOrDsToDate DISAPPEARS under.
// Databricks reads YEAR(y) as a Year over a TsOrDsToDate and writes
// it back as YEAR(y) -- the wrapper is written only where its
// parent is not one of these, which is a rule about the PARENT and
// so invisible to a probe that renders a node on its own.
TsOrDsParents map[string]struct{}
// ConvertBuildsConvert: CONVERT(type, value) is a Convert here and a
// CAST written another way everywhere else.
ConvertBuildsConvert bool
// The four conventions a PIVOT node carries that the statement never
// says: how output columns are named, and three flags stamped on.
// VersionRangeSep is the word between the two bounds of a FOR
// SYSTEM_TIME range, which are held as a Tuple: `c TO d`, `c AND d`.
VersionRangeSep map[string]string
// ForClauseOptions is the option vocabulary of FOR XML and FOR JSON,
// by kind: each word, and the second word it may take after it.
ForClauseOptions map[string]map[string][]string
// QueryHintOptions is T-SQL's OPTION (...) vocabulary: each word,
// and the words that may follow it. QueryHintOptionsNeedEqual are
// the ones written with `=` before their value.
QueryHintOptions map[string][][]string
QueryHintOptionsNeedEqual map[string]struct{}
// TableSampleWord and SelectSampleWord are what a sample is called
// after a TABLE and after the QUERY: DuckDB says TABLESAMPLE for the
// one and USING SAMPLE for the other, for the very same node.
// GroupConcatOrder says where a folded ORDER BY goes when a
// GroupConcat is written back: inside the first argument, or
// unfolded into a WITHIN GROUP. Empty means neither, and refuse.
// WithinGroupFolds are the function NAMES whose builder swallows a
// following WITHIN GROUP instead of being wrapped by one. It is the
// NAME that decides, not the class: Databricks folds STRING_AGG and
// not LISTAGG, and both build a GroupConcat.
WithinGroupFolds map[string]struct{}
// MapBraceLiteral: `MAP {k: v}` is a map LITERAL here. Elsewhere MAP
// is an ordinary name and the braces are a struct.
MapBraceLiteral bool
// TruncatesCatalog: a three-part name is written with only two of
// them here, which names a different object.
TruncatesCatalog bool
// HoistsInsertWith: a WITH inside an INSERT is written in FRONT of
// the statement here, and left where it was written elsewhere.
HoistsInsertWith bool
// ReturningWord is what this dialect calls a RETURNING clause, and
// ReturningEnd whether it is written after the WHERE rather than
// straight after the verb.
ReturningWord string
ReturningEnd bool
// MergeWithoutTarget: a MERGE branch's assignments are written without
// the target's own name in front of them here.
MergeWithoutTarget bool
// NormalizeUnquoted and NormalizeQuoted are the case a name is COMPARED
// in -- lower, upper, or empty for as-written.
NormalizeUnquoted string
NormalizeQuoted string
// CreateExistsWritten says, per kind, whether IF NOT EXISTS survives
// being written. TemporaryWritten says the same of TEMPORARY.
CreateExistsWritten map[string]bool
TemporaryWritten map[string]bool
// ViewColumnCommentWritten: a view column keeps its COMMENT here.
ViewColumnCommentWritten bool
// AlterAddColumnWord: an ALTER writes the word COLUMN after ADD here,
// and AlterRepeatsAdd whether each added column gets its own ADD.
AlterAddColumnWord bool
AlterRepeatsAdd bool
// AlterColumnTypeWord is what comes between an altered column and its
// new type -- SET DATA TYPE, TYPE, or nothing at all.
AlterColumnTypeWord string
// PrimaryKeyMembersOrdered: a table-level PRIMARY KEY names its columns
// as ordered index members here, not as bare names.
PrimaryKeyMembersOrdered bool
// UniqueConstraintWritten: a UNIQUE constraint survives being written
// here. Where it does not, the guarantee would be silently dropped.
UniqueConstraintWritten bool
// FunctionReturnsPlace says WHERE a RETURNS property is written, per
// shape of what it holds: after the parameter list, in the body, or
// nowhere at all.
FunctionReturnsPlace map[string]string
// FunctionPropertiesWritten: a function's other properties -- LANGUAGE,
// IMMUTABLE, STRICT -- survive being written here.
FunctionPropertiesWritten bool
// FunctionReturnAs: AS is written in front of a RETURN body.
FunctionReturnAs bool
// FunctionWrapsTableBody: a table-valued function's body becomes a
// RETURN here even when it was not written as one.
FunctionWrapsTableBody bool
// FunctionAsTableRead: `AS TABLE <query>` is READ as a return type here.
FunctionAsTableRead bool
// ReturnWord is the word a RETURN writes, empty where it writes none.
ReturnWord string
// ParameterModePrefix: a parameter's mode is written in FRONT of it
// here rather than after its type, and ParameterModeWords how each is
// spelled -- one word or two.
ParameterModePrefix bool
ParameterModeWords map[string]string
// SetItemSeparator sits between a configuration name and its value.
SetItemSeparator string
// ComputedColumnSpelling is how a computed column is written, with
// {expr} where the expression goes, and ComputedKeepsType whether the
// column's declared type survives beside it.
ComputedColumnSpelling string
ComputedKeepsType bool
// IdentityWritten: a GENERATED ... AS IDENTITY column keeps that
// spelling here rather than being rewritten into something else.
IdentityWritten bool
// IdentityWidensType: an identity column's type is widened to BIGINT.
IdentityWidensType bool
// GeneratedExpressionIsComputed: `GENERATED ALWAYS AS (x)` with no
// STORED is a COMPUTED column here, not an identity with an
// expression on it.
GeneratedExpressionIsComputed bool
// GeneratedStoredSetsPersisted: `GENERATED ALWAYS AS (x) STORED`
// records WHICH of STORED and VIRTUAL it read -- MySQL's own
// override does; PostgreSQL's does not, having no VIRTUAL to tell
// STORED apart from in the first place.
GeneratedStoredSetsPersisted bool
// IndexOnWord sits between an index and the table it is on.
IndexOnWord string
// StringClassSQL is how each kind of quoted string is written, keyed by
// class. The value is the template, a tab, and whether the body takes a
// string's own escaping. A class missing from the map is one this
// dialect writes in a way that loses the value.
StringClassSQL map[string]string
// OffsetRowsWord is written after an OFFSET count, and is empty in
// every dialect but T-SQL.
OffsetRowsWord string
// IntervalUnitAliases are the unit spellings an INTERVAL normalises,
// keyed by the upper-cased spelling written.
IntervalUnitAliases map[string]string
// TableHintsWritten: a table's locking hints survive here. Every
// dialect but T-SQL drops them.
TableHintsWritten bool
// TransactionWord is written after BEGIN, COMMIT and ROLLBACK here.
// TransactionSavepointWritten says whether the name a ROLLBACK TO
// carries survives, and TransactionNameWritten whether the name the
// TRANSACTION itself carries does. The dialects disagree about the two
// in opposite directions.
TransactionWord string
TransactionSavepointWritten bool
TransactionNameWritten bool
// BareBeginIsATransaction: a BEGIN with no TRANSACTION after it opens
// one here. In T-SQL it opens a block instead.
BareBeginIsATransaction bool
// SetItemKindWritten says whether a SET's scope word survives, per
// word. Dropping one changes which scope the setting belongs to.
SetItemKindWritten map[string]bool
// SetItemVariableSeparator sits between a VARIABLE and its value,
// which is not always what sits between a setting and its value.
SetItemVariableSeparator string
// SetWithoutASign: a SET may be written with no `=` between the name
// and the value here.
SetWithoutASign bool
// PartitionSQL is how a table's PARTITION clause is written, with
// {members} where its members go.
PartitionSQL string
// AlterSetOptionWritten: an `ALTER TABLE ... SET` keeps the words that
// say WHAT it sets, and AlterSetWrapsOptions whether a list of
// settings is written in parentheses.
AlterSetOptionWritten bool
AlterSetWrapsOptions bool
// AlterSetListIsSettings: `ALTER TABLE t SET (k = v)` is a list of
// settings here rather than of table properties.
AlterSetListIsSettings bool
// AlterSetIsWrapped: `ALTER TABLE t SET (...)` puts the whole SET
// inside parentheses of the syntax's own, and what is inside them
// is read as PROPERTIES rather than as settings.
AlterSetIsWrapped bool
// KeyConstraintOptions are the words that may follow a REFERENCES or a
// key, and what may follow each of them.
KeyConstraintOptions map[string][]string
// WithDataWritten: `WITH NO DATA` survives here. It says whether the
// table is FILLED from the query or only shaped by it.
WithDataWritten bool
// EnumTypeSQL is how an ENUM type's members are written, with
// {members} in it. PostgreSQL puts a space in front of the list and
// writes the parentheses even when the list is empty; everyone else
// spells it as an ordinary parameterised type.
EnumTypeSQL string
// IdentityShortSQL is the short spelling of an identity column, with
// {start} and {increment} in it, and empty where the dialect writes
// the whole GENERATED form instead.
IdentityShortSQL string
// AutoIncrementSQL is how an auto-incrementing column is spelled, and
// is empty where the dialect writes nothing and drops the numbering.
AutoIncrementSQL string
// ValuesTableWrapped: a VALUES clause used as a TABLE is written in
// parentheses here.
ValuesTableWrapped bool
// RenameTarget says how much of a qualified name a RENAME TO writes:
// the whole thing, the last part only, or -- empty -- neither,
// because the dialect writes another statement entirely.
RenameTarget string
// RewritesCreateAsSelect: this dialect has no CREATE TABLE AS SELECT
// and the reference turns it into something else, which is a
// transformation rather than a spelling.
RewritesCreateAsSelect bool
GroupConcatOrder string
TableSampleWord string
SelectSampleWord string
PivotColumnNaming string
PivotIdentifiesStrings bool
PivotPrefixesColumns bool
UnpivotValueColumnsFirst bool
// JSONPathFunctions are the names that turn their arguments into a
// JSON PATH rather than holding them. Probed with STRING literals,
// because with the placeholder columns the generic probe uses they
// all fall back to a plain positional shape that real SQL never takes.
JSONPathFunctions map[string]JSONPathFunc
// JSONPathIsParsed: PostgreSQL keeps the string after `->` whole
// as a single key; everyone else parses it into path parts.
JSONPathIsParsed bool
// WritesIntoUnlogged: PostgreSQL keeps UNLOGGED before the table
// in SELECT ... INTO; T-SQL has no such kind and drops it.
WritesIntoUnlogged bool
// JSONPath is how this dialect writes a path, in pieces: DuckDB
// quotes the whole thing and keeps the $ root, Databricks does
// neither, and the two spell a key that needs quoting differently.
// PROBED by subtraction.
JSONPath JSONPathSQL
// JSONPathByClass overrides those pieces for a class that writes a
// path differently from the standalone rendering. Only the SEPARATORS
// are overridden; the wrapper comes from the call's own spelling.
JSONPathByClass map[string]JSONPathSQL
// JSONExtractSQL is how the operator wraps a path, where the
// dialect writes it as one. A dialect that explodes the path into
// arguments has no entry and is refused.
JSONExtractSQL map[string]string
// JSONPerPartSQL is for dialects with no single path literal:
// PostgreSQL writes one operator per part, or one ARGUMENT per
// part when the node is not restricted to JSON types. One node
// becomes N of something, which is a transform, not a spelling.
JSONPerPartSQL map[string]JSONPerPart
BracketIsRewritten bool
// IndexOffset is how far this dialect's subscripts are from
// sqlglot's 0-based Bracket: 1 in DuckDB and PostgreSQL, 0
// elsewhere. The parser subtracts it from a written index.
IndexOffset int
// SafeToEliminateDoubleNegation gates the optimizer's NOT NOT x
// -> x rule. True in every dialect this port configures, which is
// exactly why it is read rather than assumed: a rule that is right
// everywhere today is not the same as a rule with no condition.
SafeToEliminateDoubleNegation bool
// Placeholder is how a bound parameter is written: `$name` in
// DuckDB, `%(name)s` in PostgreSQL, `:name` elsewhere.
Placeholder PlaceholderSQL
// QuantifierWrapsSubquery: whether a quantifier over a QUERY
// keeps the Subquery wrapper. ANY does and ALL does not, in
// every dialect -- a per-class fact, not a per-dialect one.
QuantifierWrapsSubquery map[string]bool
// QuantifierQuerySQL is the same over a QUERY, where the
// spacing and the parentheses both differ from the array form.
QuantifierQuerySQL map[string]string
// QuantifierComparisonRewritten: `a = ANY (...)` is written as some
// other call entirely (ClickHouse's `has`), which the port does not
// perform, so a comparison against a quantifier is refused.
QuantifierComparisonRewritten bool
// NestedTypeKinds are the DataType kinds the reference marks
// `nested`, whether or not they were written with parameters.
// StructTypeKinds is the subset whose parameters are NAMED
// fields (ColumnDef) rather than bare types.
NestedTypeKinds map[string]bool
StructTypeKinds map[string]bool
// SupportsFixedSizeArrays: whether `INT[3]` is a type at all.
// Where it is not, the reference RETREATS and reads the
// brackets as a subscript of the cast instead.
SupportsFixedSizeArrays bool
// SupportsBetweenFlags: whether SYMMETRIC and ASYMMETRIC survive
// on a BETWEEN as words of their own. Where they do not, a TRUE
// SYMMETRIC needs expanding into two BETWEENs joined by OR --
// not yet ported, so it is refused rather than half-written; an
// ASYMMETRIC there is simply dropped, meaning the same thing.
SupportsBetweenFlags bool
CompositeType CompositeTypeSQL
// Boolean is how TRUE and FALSE are written, and the two
// positions can differ: T-SQL writes 1 where a value is wanted
// and (1 = 1) where a condition is.
// QuantifierSQL is the text before a quantifier’s operand: ALL
// takes a trailing space and ANY does not.
QuantifierSQL map[string]string
// WritesNullsOrdering: whether NULLS FIRST/LAST is written back.
// T-SQL has no such clause and drops it.
// DefaultNullsFirst* is where NULLs sort when the statement does
// not say, per direction. Read off the reference rather than
// derived twice -- deriving it in the generator as well as the
// parser got Databricks wrong.
DefaultNullsFirstAsc bool
DefaultNullsFirstDesc bool
// WithinGroupAbsorbedBy are the classes that FOLD a following
// WITHIN GROUP into themselves instead of being wrapped by it.
WithinGroupAbsorbedBy map[string]bool
WritesNullsOrdering bool
Boolean BooleanSQL
WritesBooleanLiteral bool
IsNotNullWrapsInNot bool
// NullOrdering decides where NULLs sort when nobody says, and so
// what nulls_first records on an Ordered node. It differs per
// dialect and is not derivable from ASC or DESC alone.
NullOrdering string
// A trailing ORDER BY, LIMIT or OFFSET after a set operation belongs to
// the set operation, not to the query on its right. The reference
// parses it onto the right-hand query and then moves it up; which of
// the three move differs per dialect.
ModifiersAttachedToSetOp bool
SetOpModifiers []string
// The precedence chain, level by level, token to node class. These are
// per dialect and not interchangeable: DuckDB reads ^ as Pow where the
// default reads it as BitwiseXor.
Disjunction map[TokenType]string
Conjunction map[TokenType]string
Equality map[TokenType]string
Comparison map[TokenType]string
Bitwise map[TokenType]string
Term map[TokenType]string
Factor map[TokenType]string
Exponent map[TokenType]string
// JoinSides, JoinKinds and JoinMethods are the words that may precede
// JOIN. A method -- NATURAL, ASOF, POSITIONAL -- changes what the join
// means and is refused rather than dropped.
JoinSides map[TokenType]struct{}
JoinKinds map[TokenType]struct{}
JoinMethods map[TokenType]struct{}
// WithinGroupInside: the ordering an ordered-set aggregate is
// computed over is written INSIDE the call here rather than after it
// in a WITHIN GROUP of its own. DuckDB is the only one, and it moves
// a percentile's order key into the call's first argument as well.
WithinGroupInside bool
// PercentileClasses are the ordered-set aggregates whose ARGUMENTS a
// dialect writing the order inside reshuffles: the key becomes the
// first and the fraction slides right.
PercentileClasses map[string]struct{}
// IgnoreNullsInFunc: `IGNORE NULLS` is written INSIDE the call's
// argument list here rather than after the call.
IgnoreNullsInFunc bool
// ConditionCoercion is how a value that is not already a condition
// is made into one, with {value} standing for it. T-SQL has no boolean
// type and compares against zero instead; empty where the dialect
// takes a value as a condition unchanged.
ConditionCoercion string
// SplitPartCountsBackwards is how a dialect that counts the pieces
// of a DOTTED name from the other end opens that call, with {this} in
// it; the number and the closing parenthesis are the writer's. Empty
// where the dialect splits on any delimiter it is given.
SplitPartCountsBackwards string
// FileFormatSQL is how the storage format a table is written in is
// spelled, with {name} standing for the format. Databricks says
// `USING PARQUET` where the rest say `FORMAT=PARQUET`.
FileFormatSQL string
// TemporarySuffix is what a dialect APPENDS to a temporary object
// of each kind: Databricks gives a temporary TABLE a storage format
// it was never given.
TemporarySuffix map[string]string
// DateDeltaIsAnOperator: a date shifted by an interval is written
// with an OPERATOR here -- `d + INTERVAL 1 DAY` -- rather than as a
// call. The unit rides on the interval either way.
DateDeltaIsAnOperator bool
// ColumnCommentWritten: a COMMENT on a column survives here.
// PostgreSQL and DuckDB have nowhere to say it in a CREATE and write
// nothing, which is what the reference does with it.
ColumnCommentWritten bool
// CommaUnnestJoins: a comma join over an UNNEST is written here as
// an explicit JOIN with `ON TRUE`, because the comma form does not
// bind the unnested rows to the row they came from.
CommaUnnestJoins bool
// TableSample is how a sampling clause is written: the words that
// open it, whether the METHOD is written, whether a bare size counts
// ROWS or a percentage, and what the repeatable seed is called.
TableSample TableSampleSQL
// JSONExtractTwiceSQL is how a dialect that writes the value TWICE
// spells an extraction: T-SQL asks JSON_QUERY for an object and
// JSON_VALUE for a scalar and takes whichever is not null. Empty where
// the dialect writes the value once.
JSONExtractTwiceSQL map[string]string
// RegexpFlagArgs names which argument of each regexp call holds the
// FLAGS: `modifiers` on a replacement, `parameters` on an extraction.
RegexpFlagArgs map[string]string
// RegexpFlags are the flag characters a REGEXP_REPLACE may carry
// here, and RegexpFlagsNeedLiteral whether they have to be written as
// a string. An empty RegexpFlags means the dialect writes whatever it
// is given; a dialect that writes none at all has
// RegexpFlagsWritten false and the port refuses rather than dropping
// them, because a flag says what the replacement DOES.
RegexpFlags string
RegexpFlagsWritten bool
RegexpFlagsNeedLiteral bool
// IgnoreNullsWindowFuncs are the calls that KEEP their null
// treatment where the dialect writes it inside; IgnoreNullsDropped
// are the ones it drops silently because they ignore nulls anyway.
// Anything else the dialect calls unsupported, and so does the port.
IgnoreNullsWindowFuncs map[string]struct{}
IgnoreNullsDropped map[string]struct{}
// WithinGroupPercentile is what a PERCENTILE under a WITHIN GROUP
// becomes: "outside" keeps the clause, "inside" folds it into the
// call and reshuffles the arguments, and empty means the dialect
// writes a different function and the port refuses.
WithinGroupPercentile string
// JoinHints are the words a dialect allows between the KIND and the
// JOIN, naming how the engine should do it: `INNER HASH JOIN`. They
// are words rather than tokens, and a dialect that names none writes
// none -- the reference drops a hint where the target has no hints.
JoinHints map[string]struct{}
// RangeTokens are the operators the reference handles at the range
// level -- IS, IN, BETWEEN, the LIKE family and a dozen operators
// specific to one dialect. The ones not handled are refused here
// rather than left to look like the end of the expression.
RangeTokens map[TokenType]struct{}
// TypeDispatchFunctions are the names whose CLASS depends on the
// TYPE of one argument. DuckDB's DATE_TRUNC builds a DateTrunc
// over a DATE and a TimestampTrunc over anything else -- two
// different shapes, not just two names, which is why each carries
// a whole spec. Answerable only with a type annotator, which is
// why these were refused until there was one.
TypeDispatchFunctions map[string]TypeDispatch
// ValueDispatchFunctions are names whose CLASS is chosen by the
// WORD in one argument: T-SQL's HASHBYTES('SHA1', x) is an SHA and
// HASHBYTES('MD5', x) an MD5. A word not listed takes Default.
ValueDispatchFunctions map[string]ValueDispatch
// CreateProperties are the words that may stand between CREATE and
// what it creates, each carrying a bare property of its own:
// MATERIALIZED, UNLOGGED, TRANSIENT. The class is read off the tree,
// not made from the word -- STREAMING becomes a StreamingTableProperty.
CreateProperties map[string]string
// KeepsUnnamedWrapped are the names whose wrapped slot keeps the
// NODE where the argument has no name to take, rather than building
// something else: PostgreSQL's DATE_BIN takes a subquery as its unit.
KeepsUnnamedWrapped map[string]struct{}
// UserDefinedTypeIsIdentifier wraps such a type's NAME in an
// Identifier. PostgreSQL does and the rest keep the word as it
// stands, which is a difference the dump shows and nothing else does.
UserDefinedTypeIsIdentifier bool
// CreateKinds are the things this dialect will CREATE. T-SQL alone
// spells a procedure PROC as well as PROCEDURE.
CreateKinds map[string]struct{}
// CreateOrFlags are the words after CREATE OR and the flag each
// turns on: REPLACE and T-SQL's ALTER both mean `replace`, and
// Databricks' REFRESH means `refresh`.
CreateOrFlags map[string]string
// CreateFlagWords is how each of those flags is WRITTEN, which need
// not be the word it was read from: T-SQL reads OR REPLACE and OR
// ALTER alike and writes OR ALTER.
CreateFlagWords map[string]string
// ArityKindSpecs are the shapes an arity takes when one argument is
// of a particular kind, beside the plain shape in FunctionsByArity.
ArityKindSpecs map[string]map[int][]KindSpec
// ValidIntervalUnits are the words that can follow INTERVAL as a
// TYPE. Where the next word is not one, the reference builds a
// bare INTERVAL type instead of reading a unit that is not there.
ValidIntervalUnits map[string]struct{}
// BinaryRangeOps are the range operators that are just a binary
// node -- PostgreSQL's `@>`, `&&`, `-|-` and the rest. Probed by
// running `a <op> b` and keeping the class where the result is
// really a plain two-argument binary; IS, IN and BETWEEN have
// shapes of their own and are not here.
BinaryRangeOps map[TokenType]string
// SwappedRangeOps are the ones whose operands go the OTHER way
// round: PostgreSQL's `x @@ y` is a MatchAgainst of y over x.
SwappedRangeOps map[TokenType]struct{}
// ListedRangeOps hold one operand as a LIST of one, which is the
// reference's shape for `@@` rather than a second operand.
ListedRangeOps map[TokenType]struct{}
// BinaryRangeSQL is how each of those is written back.
BinaryRangeSQL map[string]string
// JSONOperatorsAtBitwise are the operators this dialect reads
// level with `||` rather than as an accessor binding tighter
// than arithmetic. Probed by the asymmetry: `1 + x <op> 'y'` is
// `(1 + x) <op> 'y'` where the operator is here, and
// `1 + (x <op> 'y')` where it is not. Includes `->` / `->>` in
// PostgreSQL and DuckDB, and `#>` / `#>>` / `?` in PostgreSQL.
JSONOperatorsAtBitwise map[TokenType]string
// JSONOperatorSQL is how each of those is written back -- except
// the arrows, which have a path-aware writer of their own. Only
// ever in the dialect that reads the operator at this tier:
// elsewhere the same node is a function call.
JSONOperatorSQL map[string]string
// TypeTokens maps a type keyword to the DataType.Type member the
// reference records. A few type tokens have no member and are absent,
// which refuses them rather than inventing one.
TypeTokens map[TokenType]string
// TimestampTypeTokens are the types a WITH/WITHOUT TIME ZONE may
// follow, and TimeTypeTokens the ones among them that become a
// TIMETZ rather than a TIMESTAMPTZ when it says WITH.
TimestampTypeTokens map[TokenType]struct{}
TimeTypeTokens map[TokenType]struct{}
}
ParserTables is one dialect's resolved parser vocabulary.
type PlaceholderSQL ¶
type PlaceholderSQL struct {
Named string
Anonymous string
Parameter string
// The node CLASS each spelling means in this dialect, empty
// where the dialect has no such spelling. `@nm` is a Parameter
// everywhere but DuckDB, where `@` is absolute value.
DollarName string
DollarNumber string
AtName string
PercentNamed string
PercentAnonymous string
// AnonymousJDBC: PostgreSQL stamps `jdbc` on a bare `?`, and
// writes that node back as `?` where a plain one is `%s`.
AnonymousJDBC bool
AnonymousJDBCSQL string
// WidgetPlaceholder: Databricks reads `{name}` as a notebook
// widget reference, a Placeholder with a flag of its own -- the
// one dialect where a brace opens a placeholder rather than a
// struct literal.
WidgetPlaceholder bool
}
PlaceholderSQL is the text around a bound parameter.
type PropertySpec ¶
type PropertySpec struct {
Class string
Shape string
Equals bool
// Named marks a word that takes a NAME before its list: T-SQL's
// `ON b (c)` names a partition scheme and the column it splits by.
// A word without it is handed the whole of `b (c)` as one call.
Named bool
}
PropertySpec is one word a CREATE may say about the thing it makes: the node it builds, the shape of what follows the word, and whether an equals sign may stand between them.
type Routine ¶
type Routine struct {
Kind string // PROCEDURE or FUNCTION; PROC reads as PROCEDURE
Schema, Name string
OrAlter bool // CREATE OR ALTER (or OR REPLACE)
Params []Param
// Returns is what a function returns -- a DataType, the Var TABLE, or a
// Schema of the columns a named table returns -- and nil for a procedure.
Returns *Expression
// Body is a Block of statements, or a function's Return.
Body *Expression
}
Routine is what a CREATE PROCEDURE or CREATE FUNCTION says about the routine it makes.
func RoutineOf ¶
func RoutineOf(e *Expression) (Routine, error)
RoutineOf reads the routine a CREATE PROCEDURE or CREATE FUNCTION tree makes. Any other tree is an error.
type ScriptResult ¶ added in v1.0.4
type ScriptResult struct {
Tree *Expression `json:"-"`
Diagnostics []ParseDiagnostic `json:"diagnostics"`
Complete bool `json:"complete"`
}
func ParseScript ¶ added in v1.0.4
func ParseScript(sql, dialect string) (ScriptResult, error)
type SyntaxTemplate ¶
type SyntaxTemplate struct {
Keys []string
Marked []string
Required []FuncConst
Template string
// Bracketed are the keys this dialect wraps in parentheses by
// PRECEDENCE where the operand is not an atom: DuckDB writes
// `d + INTERVAL 1 DAY` for a literal and `d + INTERVAL (x) DAY` for
// anything else. The template keeps them bare and the writer puts the
// brackets back where the operand needs them.
Bracketed []string
}
type TableSampleSQL ¶
type TableSampleSQL struct {
Keywords string
SeedKeyword string
WithMethod bool
SizeIsRows bool
RequiresParens bool
SizeIsPercent bool
}
JSONPerPart is how one path part is written, folded left over the parts: Chain for the operator form, Call for the function form. TableSampleSQL is how a sampling clause is written.
type Token ¶
type Token struct {
Type TokenType
Text string
Line int
Col int
Start int
End int
Comments []string
}
Token is one lexical token. The fields, and their meanings, are the reference's: Start and End are inclusive rune offsets into the statement, Line and Col are 1-based, and Comments holds the comments attached to this token -- leading comments attach to the token that follows, trailing ones to the token that precedes.
type TokenError ¶
TokenError reports a statement the tokenizer cannot lex -- an unterminated string, most often.
Snippet is a window of the statement around the failure, the same window the reference puts in its message. It is caller text: a table name, a literal, whatever stood there. Error() does not include it, so logging the error cannot leak it; a caller that needs the window reads the field.
func (*TokenError) Error ¶
func (e *TokenError) Error() string
type TokenType ¶
type TokenType int
TokenType identifies a lexical token. Values match the reference's IntEnum.
const ( TokL_PAREN TokenType = 1 TokR_PAREN TokenType = 2 TokL_BRACKET TokenType = 3 TokR_BRACKET TokenType = 4 TokL_BRACE TokenType = 5 TokR_BRACE TokenType = 6 TokCOMMA TokenType = 7 TokDOT TokenType = 8 TokDASH TokenType = 9 TokPLUS TokenType = 10 TokCOLON TokenType = 11 TokDOTCOLON TokenType = 12 TokDOTCARET TokenType = 13 TokDCOLON TokenType = 14 TokDCOLONDOLLAR TokenType = 15 TokDCOLONPERCENT TokenType = 16 TokDCOLONQMARK TokenType = 17 TokDQMARK TokenType = 18 TokSEMICOLON TokenType = 19 TokSTAR TokenType = 20 TokBACKSLASH TokenType = 21 TokSLASH TokenType = 22 TokLT TokenType = 23 TokLTE TokenType = 24 TokGT TokenType = 25 TokGTE TokenType = 26 TokNOT TokenType = 27 TokEQ TokenType = 28 TokNEQ TokenType = 29 TokNULLSAFE_EQ TokenType = 30 TokCOLON_EQ TokenType = 31 TokCOLON_GT TokenType = 32 TokNCOLON_GT TokenType = 33 TokAND TokenType = 34 TokOR TokenType = 35 TokAMP TokenType = 36 TokDPIPE TokenType = 37 TokPIPE_GT TokenType = 38 TokPIPE TokenType = 39 TokPIPE_SLASH TokenType = 40 TokDPIPE_SLASH TokenType = 41 TokCARET TokenType = 42 TokCARET_AT TokenType = 43 TokTILDE TokenType = 44 TokARROW TokenType = 45 TokDARROW TokenType = 46 TokFARROW TokenType = 47 TokHASH TokenType = 48 TokHASH_ARROW TokenType = 49 TokDHASH_ARROW TokenType = 50 TokLR_ARROW TokenType = 51 TokLLRR_ARROW TokenType = 52 TokDAT TokenType = 53 TokAT_QMARK TokenType = 54 TokLT_AT TokenType = 55 TokAT_GT TokenType = 56 TokDOLLAR TokenType = 57 TokPARAMETER TokenType = 58 TokSESSION TokenType = 59 TokSESSION_PARAMETER TokenType = 60 TokSESSION_USER TokenType = 61 TokDAMP TokenType = 62 TokAMP_LT TokenType = 63 TokAMP_GT TokenType = 64 TokADJACENT TokenType = 65 TokXOR TokenType = 66 TokDSTAR TokenType = 67 TokQMARK_AMP TokenType = 68 TokQMARK_PIPE TokenType = 69 TokHASH_DASH TokenType = 70 TokEXCLAMATION TokenType = 71 TokURI_START TokenType = 72 TokBLOCK_START TokenType = 73 TokBLOCK_END TokenType = 74 TokSPACE TokenType = 75 TokBREAK TokenType = 76 TokSTRING TokenType = 77 TokNUMBER TokenType = 78 TokIDENTIFIER TokenType = 79 TokDATABASE TokenType = 80 TokCOLUMN TokenType = 81 TokCOLUMN_DEF TokenType = 82 TokSCHEMA TokenType = 83 TokTABLE TokenType = 84 TokWAREHOUSE TokenType = 85 TokSTAGE TokenType = 86 TokSTREAM TokenType = 87 TokSTREAMLIT TokenType = 88 TokVAR TokenType = 89 TokBIT_STRING TokenType = 90 TokHEX_STRING TokenType = 91 TokBYTE_STRING TokenType = 92 TokNATIONAL_STRING TokenType = 93 TokRAW_STRING TokenType = 94 TokHEREDOC_STRING TokenType = 95 TokUNICODE_STRING TokenType = 96 TokBIT TokenType = 97 TokBOOLEAN TokenType = 98 TokTINYINT TokenType = 99 TokUTINYINT TokenType = 100 TokSMALLINT TokenType = 101 TokUSMALLINT TokenType = 102 TokMEDIUMINT TokenType = 103 TokUMEDIUMINT TokenType = 104 TokINT TokenType = 105 TokUINT TokenType = 106 TokBIGINT TokenType = 107 TokUBIGINT TokenType = 108 TokBIGNUM TokenType = 109 TokINT128 TokenType = 110 TokUINT128 TokenType = 111 TokINT256 TokenType = 112 TokUINT256 TokenType = 113 TokFLOAT TokenType = 114 TokDOUBLE TokenType = 115 TokUDOUBLE TokenType = 116 TokDECIMAL TokenType = 117 TokDECIMAL32 TokenType = 118 TokDECIMAL64 TokenType = 119 TokDECIMAL128 TokenType = 120 TokDECIMAL256 TokenType = 121 TokDECFLOAT TokenType = 122 TokUDECIMAL TokenType = 123 TokBIGDECIMAL TokenType = 124 TokCHAR TokenType = 125 TokNCHAR TokenType = 126 TokVARCHAR TokenType = 127 TokNVARCHAR TokenType = 128 TokBPCHAR TokenType = 129 TokTEXT TokenType = 130 TokMEDIUMTEXT TokenType = 131 TokLONGTEXT TokenType = 132 TokBLOB TokenType = 133 TokMEDIUMBLOB TokenType = 134 TokLONGBLOB TokenType = 135 TokTINYBLOB TokenType = 136 TokTINYTEXT TokenType = 137 TokNAME TokenType = 138 TokBINARY TokenType = 139 TokVARBINARY TokenType = 140 TokJSON TokenType = 141 TokJSONB TokenType = 142 TokTIME TokenType = 143 TokTIMETZ TokenType = 144 TokTIME_NS TokenType = 145 TokTIMESTAMP TokenType = 146 TokTIMESTAMPTZ TokenType = 147 TokTIMESTAMPLTZ TokenType = 148 TokTIMESTAMPNTZ TokenType = 149 TokTIMESTAMP_S TokenType = 150 TokTIMESTAMP_MS TokenType = 151 TokTIMESTAMP_NS TokenType = 152 TokDATETIME TokenType = 153 TokDATETIME2 TokenType = 154 TokDATETIME64 TokenType = 155 TokSMALLDATETIME TokenType = 156 TokDATE TokenType = 157 TokDATE32 TokenType = 158 TokINT4RANGE TokenType = 159 TokINT4MULTIRANGE TokenType = 160 TokINT8RANGE TokenType = 161 TokINT8MULTIRANGE TokenType = 162 TokNUMRANGE TokenType = 163 TokNUMMULTIRANGE TokenType = 164 TokTSRANGE TokenType = 165 TokTSMULTIRANGE TokenType = 166 TokTSTZRANGE TokenType = 167 TokTSTZMULTIRANGE TokenType = 168 TokDATERANGE TokenType = 169 TokDATEMULTIRANGE TokenType = 170 TokUUID TokenType = 171 TokGEOGRAPHY TokenType = 172 TokGEOGRAPHYPOINT TokenType = 173 TokNULLABLE TokenType = 174 TokGEOMETRY TokenType = 175 TokPOINT TokenType = 176 TokRING TokenType = 177 TokLINESTRING TokenType = 178 TokLOCALTIME TokenType = 179 TokLOCALTIMESTAMP TokenType = 180 TokSYSTIMESTAMP TokenType = 181 TokMULTILINESTRING TokenType = 182 TokPOLYGON TokenType = 183 TokMULTIPOLYGON TokenType = 184 TokHLLSKETCH TokenType = 185 TokHSTORE TokenType = 186 TokSUPER TokenType = 187 TokSERIAL TokenType = 188 TokSMALLSERIAL TokenType = 189 TokBIGSERIAL TokenType = 190 TokXML TokenType = 191 TokYEAR TokenType = 192 TokUSERDEFINED TokenType = 193 TokMONEY TokenType = 194 TokSMALLMONEY TokenType = 195 TokROWVERSION TokenType = 196 TokIMAGE TokenType = 197 TokVARIANT TokenType = 198 TokOBJECT TokenType = 199 TokINET TokenType = 200 TokIPADDRESS TokenType = 201 TokIPPREFIX TokenType = 202 TokIPV4 TokenType = 203 TokIPV6 TokenType = 204 TokENUM TokenType = 205 TokENUM8 TokenType = 206 TokENUM16 TokenType = 207 TokFIXEDSTRING TokenType = 208 TokLOWCARDINALITY TokenType = 209 TokNESTED TokenType = 210 TokAGGREGATEFUNCTION TokenType = 211 TokSIMPLEAGGREGATEFUNCTION TokenType = 212 TokTDIGEST TokenType = 213 TokUNKNOWN TokenType = 214 TokVECTOR TokenType = 215 TokDYNAMIC TokenType = 216 TokVOID TokenType = 217 TokALIAS TokenType = 218 TokALTER TokenType = 219 TokALL TokenType = 220 TokANTI TokenType = 221 TokANY TokenType = 222 TokAPPLY TokenType = 223 TokARRAY TokenType = 224 TokASC TokenType = 225 TokASOF TokenType = 226 TokATTACH TokenType = 227 TokAUTO_INCREMENT TokenType = 228 TokBEGIN TokenType = 229 TokBETWEEN TokenType = 230 TokBULK_COLLECT_INTO TokenType = 231 TokCACHE TokenType = 232 TokCASE TokenType = 233 TokCHARACTER_SET TokenType = 234 TokCLUSTER_BY TokenType = 235 TokCOLLATE TokenType = 236 TokCOMMAND TokenType = 237 TokCOMMENT TokenType = 238 TokCOMMIT TokenType = 239 TokCONNECT_BY TokenType = 240 TokCONSTRAINT TokenType = 241 TokCOPY TokenType = 242 TokCREATE TokenType = 243 TokCROSS TokenType = 244 TokCUBE TokenType = 245 TokCURRENT_DATE TokenType = 246 TokCURRENT_DATETIME TokenType = 247 TokCURRENT_SCHEMA TokenType = 248 TokCURRENT_TIME TokenType = 249 TokCURRENT_TIMESTAMP TokenType = 250 TokCURRENT_USER TokenType = 251 TokCURRENT_USER_ID TokenType = 252 TokCURRENT_ROLE TokenType = 253 TokCURRENT_CATALOG TokenType = 254 TokDECLARE TokenType = 255 TokDEFAULT TokenType = 256 TokDELETE TokenType = 257 TokDESC TokenType = 258 TokDESCRIBE TokenType = 259 TokDETACH TokenType = 260 TokDICTIONARY TokenType = 261 TokDISTINCT TokenType = 262 TokDISTRIBUTE_BY TokenType = 263 TokDIV TokenType = 264 TokDROP TokenType = 265 TokELSE TokenType = 266 TokEND TokenType = 267 TokESCAPE TokenType = 268 TokEXCEPT TokenType = 269 TokEXECUTE TokenType = 270 TokEXISTS TokenType = 271 TokFALSE TokenType = 272 TokFETCH TokenType = 273 TokFILE TokenType = 274 TokFILE_FORMAT TokenType = 275 TokFILTER TokenType = 276 TokFINAL TokenType = 277 TokFIRST TokenType = 278 TokFOR TokenType = 279 TokFORCE TokenType = 280 TokFOREIGN_KEY TokenType = 281 TokFORMAT TokenType = 282 TokFROM TokenType = 283 TokFULL TokenType = 284 TokFUNCTION TokenType = 285 TokGET TokenType = 286 TokGLOB TokenType = 287 TokGLOBAL TokenType = 288 TokGRANT TokenType = 289 TokGROUP_BY TokenType = 290 TokGROUPING_SETS TokenType = 291 TokHAVING TokenType = 292 TokHINT TokenType = 293 TokIGNORE TokenType = 294 TokILIKE TokenType = 295 TokIN TokenType = 296 TokINDEX TokenType = 297 TokINDEXED_BY TokenType = 298 TokINNER TokenType = 299 TokINSERT TokenType = 300 TokINSTALL TokenType = 301 TokINTEGRATION TokenType = 302 TokINTERSECT TokenType = 303 TokINTERVAL TokenType = 304 TokINTO TokenType = 305 TokINTRODUCER TokenType = 306 TokIRLIKE TokenType = 307 TokIS TokenType = 308 TokISNULL TokenType = 309 TokJOIN TokenType = 310 TokJOIN_MARKER TokenType = 311 TokKEEP TokenType = 312 TokKEY TokenType = 313 TokKILL TokenType = 314 TokLANGUAGE TokenType = 315 TokLATERAL TokenType = 316 TokLEFT TokenType = 317 TokLIKE TokenType = 318 TokLIMIT TokenType = 319 TokLIST TokenType = 320 TokLOAD TokenType = 321 TokLOCK TokenType = 322 TokMAP TokenType = 323 TokMATCH TokenType = 324 TokMATCH_CONDITION TokenType = 325 TokMATCH_RECOGNIZE TokenType = 326 TokMEMBER_OF TokenType = 327 TokMERGE TokenType = 328 TokMOD TokenType = 329 TokMODEL TokenType = 330 TokNATURAL TokenType = 331 TokNEXT TokenType = 332 TokNOTHING TokenType = 333 TokNOTNULL TokenType = 334 TokNULL TokenType = 335 TokOBJECT_IDENTIFIER TokenType = 336 TokOFFSET TokenType = 337 TokON TokenType = 338 TokONLY TokenType = 339 TokOPERATOR TokenType = 340 TokORDER_BY TokenType = 341 TokORDER_SIBLINGS_BY TokenType = 342 TokORDERED TokenType = 343 TokORDINALITY TokenType = 344 TokOUT TokenType = 345 TokINOUT TokenType = 346 TokOUTER TokenType = 347 TokOVER TokenType = 348 TokOVERLAPS TokenType = 349 TokOVERWRITE TokenType = 350 TokPACKAGE TokenType = 351 TokPARTITION TokenType = 352 TokPARTITION_BY TokenType = 353 TokPERCENT TokenType = 354 TokPIVOT TokenType = 355 TokPLACEHOLDER TokenType = 356 TokPOLICY TokenType = 357 TokPOOL TokenType = 358 TokPOSITIONAL TokenType = 359 TokPRAGMA TokenType = 360 TokPREWHERE TokenType = 361 TokPRIMARY_KEY TokenType = 362 TokPROCEDURE TokenType = 363 TokPROPERTIES TokenType = 364 TokPROJECTION TokenType = 365 TokPSEUDO_TYPE TokenType = 366 TokPUT TokenType = 367 TokQUALIFY TokenType = 368 TokQUOTE TokenType = 369 TokQDCOLON TokenType = 370 TokRANGE TokenType = 371 TokRECURSIVE TokenType = 372 TokREFRESH TokenType = 373 TokRENAME TokenType = 374 TokREPLACE TokenType = 375 TokRETURNING TokenType = 376 TokREVOKE TokenType = 377 TokREFERENCES TokenType = 378 TokRIGHT TokenType = 379 TokRLIKE TokenType = 380 TokROLE TokenType = 381 TokROLLBACK TokenType = 382 TokROLLUP TokenType = 383 TokROW TokenType = 384 TokROWS TokenType = 385 TokRULE TokenType = 386 TokSELECT TokenType = 387 TokSEMI TokenType = 388 TokSEPARATOR TokenType = 389 TokSEQUENCE TokenType = 390 TokSERDE_PROPERTIES TokenType = 391 TokSET TokenType = 392 TokSETTINGS TokenType = 393 TokSHOW TokenType = 394 TokSIMILAR_TO TokenType = 395 TokSOME TokenType = 396 TokSORT_BY TokenType = 397 TokSOUNDS_LIKE TokenType = 398 TokSQL_SECURITY TokenType = 399 TokSTART_WITH TokenType = 400 TokSTORAGE_INTEGRATION TokenType = 401 TokSTRAIGHT_JOIN TokenType = 402 TokSTRUCT TokenType = 403 TokSUMMARIZE TokenType = 404 TokTABLE_SAMPLE TokenType = 405 TokTAG TokenType = 406 TokTEMPORARY TokenType = 407 TokTOP TokenType = 408 TokTHEN TokenType = 409 TokTRUE TokenType = 410 TokTRUNCATE TokenType = 411 TokTRIGGER TokenType = 412 TokTYPE TokenType = 413 TokUNCACHE TokenType = 414 TokUNDROP TokenType = 415 TokUNION TokenType = 416 TokUNNEST TokenType = 417 TokUNPIVOT TokenType = 418 TokUPDATE TokenType = 419 TokUSE TokenType = 420 TokUSING TokenType = 421 TokVALUES TokenType = 422 TokVARIADIC TokenType = 423 TokVIEW TokenType = 424 TokSEMANTIC_VIEW TokenType = 425 TokVOLATILE TokenType = 426 TokVOLUME TokenType = 427 TokWHEN TokenType = 428 TokWHERE TokenType = 429 TokWINDOW TokenType = 430 TokWITH TokenType = 431 TokUNIQUE TokenType = 432 TokUTC_DATE TokenType = 433 TokUTC_TIME TokenType = 434 TokUTC_TIMESTAMP TokenType = 435 TokOPTION TokenType = 436 TokSINK TokenType = 437 TokSOURCE TokenType = 438 TokANALYZE TokenType = 439 TokNAMESPACE TokenType = 440 TokEXPORT TokenType = 441 TokHIVE_TOKEN_STREAM TokenType = 442 TokSENTINEL TokenType = 443 )
func TokenTypeByName ¶
TokenTypeByName looks a token type up by its reference name, for tests and for reading the token expectations.
type Tokenizer ¶
type Tokenizer struct {
// contains filtered or unexported fields
}
Tokenizer turns SQL into tokens for one dialect. It is a direct port of the reference's TokenizerCore: same scan order, same lookahead, same positions. It is not safe for concurrent use; make one per goroutine, they are cheap.
func NewTokenizer ¶
NewTokenizer returns a tokenizer for a dialect. The empty name is the dialect-neutral default.
type TypeDispatch ¶
FuncSpec is how one function name becomes a node: the class, and what fills each of its argument keys. TypeDispatch is a name that builds a different node depending on the type of one of its arguments.
type UnsupportedError ¶
type UnsupportedError struct {
Construct string
Token string
Start int
End int
HasRange bool
// TokenIsKeyword reports whether Token is dialect vocabulary rather than
// something the caller wrote. Only a keyword is safe to record.
TokenIsKeyword bool
}
UnsupportedError names the construct the port could not read.
The construct is the field worth recording. A consumer that wants to know what to build next needs "PIVOT" or "window function", and reading that back out of a formatted message would be a parser of its own -- the same reason NotAQueryError carries Kind.
Construct is SQL VOCABULARY and safe to log: the seven call sites that interpolate do so with a function name, a type, a join method or a clause keyword, never with a caller's identifier. Token is the opposite -- it is whatever the statement said at the point of failure, which can be a table or column name -- so it is available to a caller that has a reason for it and is not part of Error().
func (*UnsupportedError) Error ¶
func (e *UnsupportedError) Error() string
func (*UnsupportedError) Is ¶
func (e *UnsupportedError) Is(target error) bool
Is makes errors.Is(err, ErrUnsupported) hold for this error too.
func (*UnsupportedError) Label ¶
func (e *UnsupportedError) Label() string
Label is the construct, named as precisely as can be done SAFELY -- the string to count when deciding what to build next.
Construct alone is not always enough. A window function and a PIVOT both stop the parser at "trailing tokens", the second largest refusal bucket in the fixture corpus, and the two need entirely different work. What separates them is the token: OVER, PIVOT. Those are keywords -- dialect vocabulary, fixed and public -- so appending one narrows the label without recording anything the caller wrote. When the token is an identifier, a string or a number, it is omitted, because a refusal on `WHERE email = '...'` must not put that anywhere.
Source Files
¶
- annotate.go
- annotate_gen.go
- anonymize.go
- classes_gen.go
- clickhouse.go
- clickhouse_generate.go
- clickhouse_parse.go
- config.go
- date_arith.go
- date_trunc.go
- decimal.go
- dialects_gen.go
- diff.go
- digits_gen.go
- expression.go
- format.go
- generate.go
- generate_nodes.go
- generate_tsql_cursor.go
- generate_tsql_event_session.go
- generate_tsql_routine.go
- jsonpath.go
- list_literal.go
- match_recognize.go
- match_recognize_gen.go
- mysql_forms.go
- parse_builders.go
- parse_ddl.go
- parse_dml.go
- parse_expr.go
- parse_interval.go
- parse_json_query.go
- parse_lambda.go
- parse_procedure.go
- parse_properties.go
- parse_routine.go
- parse_script.go
- parse_select.go
- parse_syntax_funcs.go
- parse_table.go
- parse_tsql_cursor.go
- parse_tsql_event_session.go
- parse_tsql_routine.go
- parse_tsql_trigger.go
- parse_window.go
- parser.go
- parser_gen.go
- propagate.go
- refresh.go
- risingwave_source.go
- simplify.go
- slice_step.go
- sqlite.go
- sqlite_generate.go
- timeformat.go
- tokenizer.go
- tokentype_gen.go
- trie.go
- tsql.go