Expand description
The SQL clauses the three dialects share, as data.
One struct per clause — With, Where, Frame, … — each an
Expression that renders only itself. A dialect’s
query type composes them as named fields and decides the order and the
separation between them; nothing here knows what statement it is part of.
§Four conventions the dialect crates depend on
Defaultmeans “clause absent”, and an absent clause renders nothing at all — not a bare keyword, not a stray space. That is what lets a query writew.write_if(!q.where_.is_empty(), " ", &q.where_, "")and never think about it again. Every clause also has anis_empty, for the cases where the query needs a separator in front.- A clause writes its own keyword, so
WhererendersWHERE a AND bandLimitrendersLIMIT 10. The single exception isSet, and the reason is grammatical: MySQL’sON DUPLICATE KEY UPDATEtakes the same assignment list with noSETin front of it, so the keyword has to belong to whatever contains the list. Clauses that are lists of independent items (Locks,Combines) write no keyword either, because each item carries its own. - Anything the caller supplies is an
Expr, never aStringor a number: aLIMITmay be a bound argument, aVALUEScell may be a sub-select, a frame bound may be$1 PRECEDING. Fields typedCow<'static, str>are identifiers and are quoted with the dialect’s own quoting; fields typed as a keyword enum are fixed SQL. - A nested context implements the same
Has*trait.ON CONFLICT … DO UPDATEhas aWHEREof its own, and so does the index-inference target in front of it, soHasWhereis implemented byConflictClauseandConflictTargetas well as by whatever statements a dialect gives one to. A mod written once therefore works in all of them.
§Keywords are enums, not strings
bob stores Type string / Direction string and exports const vocabularies.
Here a closed keyword set is an enum (FrameMode, LockStrength,
SetOp, …), because the set really is closed by the grammar and a typo in
one is otherwise a runtime syntax error. The two genuinely open-ended ones keep
an escape hatch shaped like the grammar that opened them:
JoinKind::Custom for MySQL’s STRAIGHT_JOIN, and
OrderDirection::Using for PostgreSQL’s ORDER BY … USING <operator>.
§Sub-queries
Where a clause holds one — Cte::query, Combine::query,
Values::query — it holds it as an Expr, which a
dialect’s query type reaches through
Expr::Custom. bob has a Query interface in
those slots whose only extra promise is “renders with its own dialect rather
than the one handed to it”, and a query type keeps that promise for itself by
calling
SqlWriter::write_with_dialect inside
its own write_sql.
§Rendering choices made here
Formatting is not part of the contract — the golden comparison collapses runs of whitespace — but two choices are visible through it and are deliberate:
- Identifiers are quoted. A CTE name, a
USINGcolumn, a window name, a locked table: bob writes all of these verbatim, which breaks the moment one of them is a reserved word or mixed-case. They go throughSqlWriter::push_quotedhere. - No trailing or doubled separators. bob emits
FOR KEY SHAREandUSING("id")with trailing spaces andPARTITION BY a ORDER BY bwith two, because each fragment guesses at its own padding. Every clause here writes separators only between things that are actually present.
Structs§
- Combine
UNION [ALL] (<query>)- Combines
- Every set operation chained onto one statement, and the
ORDER BY/LIMIT/OFFSET/FETCHthat belong to the combination rather than to any one operand. - Conflict
- The slot an
INSERTkeeps for its conflict handling. - Conflict
Clause ON CONFLICT [<target>] DO NOTHING | DO UPDATE SET … [WHERE …]- Conflict
Target - What the conflict is detected on: a named constraint, or an index inferred from a column list and an optional predicate.
- Cte
- One common table expression.
- CteCycle
CYCLE <cols> SET <col> [TO <value> DEFAULT <value>] USING <col>- CteSearch
SEARCH { BREADTH | DEPTH } FIRST BY <cols> SET <col>- Fetch
FETCH { FIRST | NEXT } n { ROW | ROWS } { ONLY | WITH TIES }— the SQL-standard spelling ofLIMIT, and the only one that can ask for ties.- Frame
- A window frame: which rows around the current one the window function sees.
- GroupBy
GROUP BY [DISTINCT] a, b [WITH ROLLUP]- Grouping
Set - One grouping element that is itself a set:
ROLLUP (a, b),CUBE (a, b),GROUPING SETS ((a), (b), ()). - Having
HAVING a AND b- Index
Hint - MySQL’s
USE | FORCE | IGNORE INDEX [FOR …] (indexes). - Join
[NATURAL] <kind> <table> [ON a AND b] [USING (cols) [AS alias]]- Limit
LIMIT n- Lock
FOR <strength> [OF table, …] [NOWAIT | SKIP LOCKED]- Locks
- Every
FOR …locking clause on one statement. - Named
Window name AS (<definition>)— one entry of a statement’sWINDOWclause.- Offset
OFFSET n [ ROW | ROWS ]- OrderBy
ORDER BY a, b DESC- Order
Def - One sort key:
expr [COLLATE c] [ASC | DESC | USING op] [NULLS FIRST | LAST]. - Returning
RETURNING a, b- Select
List - The projection:
SELECTa, b, c, or*when nothing was asked for. - Set
- The assignment list of an
UPDATE, or ofDO UPDATE/ON DUPLICATE KEY UPDATE. - Table
Functions - A set of set-returning functions in a
FROM, which PostgreSQL spellsROWS FROM (…)once there is more than one. - Table
Ref - A
from_item: a table, a sub-select, a function call or a CTE name, plus every decoration the three dialects hang off one, plus its joins. - Values
- Where the rows an
INSERTadds come from. - Values
Row - One parenthesised row of a
VALUESlist. - Where
WHERE a AND b AND c- Window
- A window definition: what goes inside
OVER (…), or afterWINDOW name AS. - Windows
WINDOW w AS (…), v AS (…)- With
WITH [RECURSIVE] <cte>, <cte>, …
Enums§
- Conflict
Action - What to do about a conflicting row.
- First
OrNext - The
FIRST/NEXTsynonym pair of aFETCH—gram.ycalls the productionfirst_or_next. Synonyms in the grammar, distinct on the page, exactly asRowsKeyword. - Frame
Exclusion - Which rows a frame leaves out despite their being inside it.
- Frame
Mode - What a frame’s offsets count in.
- Group
ByWith - MySQL’s trailing
WITH …modifier. - Grouping
SetKind - Which set a
GroupingSetexpands to. - Index
Hint Kind - Which way a MySQL index hint leans.
- Index
Hint Scope - What a MySQL index hint applies to.
- Indexed
By - SQLite’s index directive.
- Join
Kind - The
join_typeof a join. - Lock
Strength - How strong a row lock is, weakest last.
- Lock
Wait - What to do about a row someone else has already locked.
- Nulls
Position - Where nulls sort relative to everything else.
- Order
Direction - Which way a sort key sorts.
- Rows
Keyword - The
ROW/ROWSsynonym pair, spelled the way the human reading the SQL expects. - Search
Order - Which way a recursive CTE’s
SEARCHwalks. - SetOp
- Which set operation combines two queries.
Traits§
- HasCombines
- A statement other statements can be combined onto.
- HasConflict
- An
INSERTwith conflict handling. - HasConflict
Clause - Anything with a conflict clause of the
ON CONFLICTshape, so that the target and action mods can be written once. - HasFetch
- A statement with a
FETCHclause. - HasFrame
- Anything with a window frame — a
Windowdefinition. - HasGroup
By - A statement with a
GROUP BYclause. - HasHaving
- A statement with a
HAVINGclause. - HasJoins
- Anything joins can be appended to: a
TableRef, or a statement that keeps its joins beside its table rather than on it. - HasLimit
- A statement with a
LIMIT. - HasLocks
- A statement that can take a row lock.
- HasOffset
- A statement with an
OFFSET. - HasOrder
By - Anything with an
ORDER BY: a statement, aWindowdefinition, an aggregate’sORDER BYinside its own parentheses, or the trailing ordering of a set operation (Combines). - HasReturning
- A mutation that can return rows.
- HasSelect
List - A statement with a projection.
- HasSet
- Anything with an assignment list: an
UPDATE, or aConflictClause. - HasTable
Ref - Anything with a table reference: the
FROMof aSELECT, the target of anINSERT/UPDATE/DELETE, theUSINGof aDELETE. - HasValues
- An
INSERTwith a row source. - HasWhere
- Anything with a
WHEREclause. - HasWindow
- Anything with a window definition: a
NamedWindow, or a dialect’s function builder holding the window of itsOVER. - HasWindows
- A statement with a
WINDOWclause. - HasWith
- A statement that accepts common table expressions.