Skip to main content

Module clause

Module clause 

Source
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

  1. Default means “clause absent”, and an absent clause renders nothing at all — not a bare keyword, not a stray space. That is what lets a query write w.write_if(!q.where_.is_empty(), " ", &q.where_, "") and never think about it again. Every clause also has an is_empty, for the cases where the query needs a separator in front.
  2. A clause writes its own keyword, so Where renders WHERE a AND b and Limit renders LIMIT 10. The single exception is Set, and the reason is grammatical: MySQL’s ON DUPLICATE KEY UPDATE takes the same assignment list with no SET in 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.
  3. Anything the caller supplies is an Expr, never a String or a number: a LIMIT may be a bound argument, a VALUES cell may be a sub-select, a frame bound may be $1 PRECEDING. Fields typed Cow<'static, str> are identifiers and are quoted with the dialect’s own quoting; fields typed as a keyword enum are fixed SQL.
  4. A nested context implements the same Has* trait. ON CONFLICT … DO UPDATE has a WHERE of its own, and so does the index-inference target in front of it, so HasWhere is implemented by ConflictClause and ConflictTarget as 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 USING column, 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 through SqlWriter::push_quoted here.
  • No trailing or doubled separators. bob emits FOR KEY SHARE and USING("id") with trailing spaces and PARTITION BY a ORDER BY b with 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 / FETCH that belong to the combination rather than to any one operand.
Conflict
The slot an INSERT keeps for its conflict handling.
ConflictClause
ON CONFLICT [<target>] DO NOTHING | DO UPDATE SET … [WHERE …]
ConflictTarget
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 of LIMIT, 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]
GroupingSet
One grouping element that is itself a set: ROLLUP (a, b), CUBE (a, b), GROUPING SETS ((a), (b), ()).
Having
HAVING a AND b
IndexHint
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.
NamedWindow
name AS (<definition>) — one entry of a statement’s WINDOW clause.
Offset
OFFSET n [ ROW | ROWS ]
OrderBy
ORDER BY a, b DESC
OrderDef
One sort key: expr [COLLATE c] [ASC | DESC | USING op] [NULLS FIRST | LAST].
Returning
RETURNING a, b
SelectList
The projection: SELECT a, b, c, or * when nothing was asked for.
Set
The assignment list of an UPDATE, or of DO UPDATE / ON DUPLICATE KEY UPDATE.
TableFunctions
A set of set-returning functions in a FROM, which PostgreSQL spells ROWS FROM (…) once there is more than one.
TableRef
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 INSERT adds come from.
ValuesRow
One parenthesised row of a VALUES list.
Where
WHERE a AND b AND c
Window
A window definition: what goes inside OVER (…), or after WINDOW name AS.
Windows
WINDOW w AS (…), v AS (…)
With
WITH [RECURSIVE] <cte>, <cte>, …

Enums§

ConflictAction
What to do about a conflicting row.
FirstOrNext
The FIRST/NEXT synonym pair of a FETCHgram.y calls the production first_or_next. Synonyms in the grammar, distinct on the page, exactly as RowsKeyword.
FrameExclusion
Which rows a frame leaves out despite their being inside it.
FrameMode
What a frame’s offsets count in.
GroupByWith
MySQL’s trailing WITH … modifier.
GroupingSetKind
Which set a GroupingSet expands to.
IndexHintKind
Which way a MySQL index hint leans.
IndexHintScope
What a MySQL index hint applies to.
IndexedBy
SQLite’s index directive.
JoinKind
The join_type of a join.
LockStrength
How strong a row lock is, weakest last.
LockWait
What to do about a row someone else has already locked.
NullsPosition
Where nulls sort relative to everything else.
OrderDirection
Which way a sort key sorts.
RowsKeyword
The ROW/ROWS synonym pair, spelled the way the human reading the SQL expects.
SearchOrder
Which way a recursive CTE’s SEARCH walks.
SetOp
Which set operation combines two queries.

Traits§

HasCombines
A statement other statements can be combined onto.
HasConflict
An INSERT with conflict handling.
HasConflictClause
Anything with a conflict clause of the ON CONFLICT shape, so that the target and action mods can be written once.
HasFetch
A statement with a FETCH clause.
HasFrame
Anything with a window frame — a Window definition.
HasGroupBy
A statement with a GROUP BY clause.
HasHaving
A statement with a HAVING clause.
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.
HasOrderBy
Anything with an ORDER BY: a statement, a Window definition, an aggregate’s ORDER BY inside its own parentheses, or the trailing ordering of a set operation (Combines).
HasReturning
A mutation that can return rows.
HasSelectList
A statement with a projection.
HasSet
Anything with an assignment list: an UPDATE, or a ConflictClause.
HasTableRef
Anything with a table reference: the FROM of a SELECT, the target of an INSERT/UPDATE/DELETE, the USING of a DELETE.
HasValues
An INSERT with a row source.
HasWhere
Anything with a WHERE clause.
HasWindow
Anything with a window definition: a NamedWindow, or a dialect’s function builder holding the window of its OVER.
HasWindows
A statement with a WINDOW clause.
HasWith
A statement that accepts common table expressions.