squonk_ast/ast/stored_program.rs
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2026 Moderately AI Inc.
3
4//! MySQL stored-program (SQL/PSM) compound-statement AST nodes.
5//!
6//! The body sub-language of a routine/trigger/event: a `[label:] BEGIN … END
7//! [label]` compound block carrying a strict [`Declaration`] prefix (variables,
8//! conditions, cursors, handlers) then a statement list, plus the flow-control
9//! statements (`IF`/`CASE`/`LOOP`/`WHILE`/`REPEAT`/`LEAVE`/`ITERATE`/`RETURN`) and
10//! the cursor operations (`OPEN`/`FETCH`/`CLOSE`). These are body-context-only
11//! [`Statement`] variants: the parser reaches them through the separate
12//! `parse_body_statement` dispatcher, never the top-level one (a bare top-level
13//! `BEGIN … END` is a transaction, not a compound block).
14//!
15//! Each nesting node's payload is boxed into its [`Statement`] variant (the
16//! `CreateTrigger` precedent) so the enum stays within its 24-byte size budget; the
17//! bodies are `ThinVec<Statement<X>>`, reusing the existing statement nodes exactly
18//! as the trigger body does.
19
20use super::{DataType, Expr, Extension, Ident, Literal, NoExt, Query, Statement};
21use crate::vocab::Meta;
22use thin_vec::ThinVec;
23
24/// A `[<label>:] BEGIN [<declarations>] [<statements>] END [<label>]` compound block.
25///
26/// The declaration prefix is parse-time strict-ordered ({variables, conditions} →
27/// cursors → handlers); the [`body`](Self::body) is the trailing statement list, in
28/// source order, each element a full [`Statement`]. Both the opening `label:` and the
29/// closing `END <label>` are optional and independent surface tags — a block may carry
30/// either, both, or neither; when both are present they must match (a structural check
31/// the parser enforces).
32#[derive(Clone, Debug, PartialEq, Eq, Hash)]
33#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
34#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
35pub struct CompoundStatement<X: Extension = NoExt> {
36 /// The opening block label (`<label>:` before `BEGIN`); `None` when unlabelled.
37 pub label: Option<Ident>,
38 /// The `DECLARE` prefix, in source order (always ahead of [`body`](Self::body)).
39 pub declarations: ThinVec<Declaration<X>>,
40 /// The block's statement list, in source order.
41 pub body: ThinVec<Statement<X>>,
42 /// The closing block label (`END <label>`); `None` when the close is bare `END`.
43 pub end_label: Option<Ident>,
44 /// Source location and node identity.
45 pub meta: Meta,
46}
47
48/// One `DECLARE …` item in a [`CompoundStatement`] prefix.
49///
50/// The four forms are parsed uniformly into this prefix; their *ordering* is enforced
51/// post-hoc by the parser's declaration 4-counter ({[`Variable`](Self::Variable),
52/// [`Condition`](Self::Condition)} → [`Cursor`](Self::Cursor) →
53/// [`Handler`](Self::Handler)), mirroring the server's own mechanism rather than
54/// encoding the order as grammar productions.
55#[derive(Clone, Debug, PartialEq, Eq, Hash)]
56#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
57#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
58pub enum Declaration<X: Extension = NoExt> {
59 /// `DECLARE <name> [, <name> …] <type> [DEFAULT <expr>]` — one or more local
60 /// variables sharing a type and optional default.
61 Variable {
62 /// The declared variable names, in source order (always at least one).
63 names: ThinVec<Ident>,
64 /// The shared declared type.
65 data_type: DataType<X>,
66 /// The optional `DEFAULT <expr>` initializer.
67 default: Option<Expr<X>>,
68 /// Source location and node identity.
69 meta: Meta,
70 },
71 /// `DECLARE <name> CONDITION FOR <condition-value>` — a named condition alias.
72 Condition {
73 /// The condition name.
74 name: Ident,
75 /// The `SQLSTATE '…'` or MySQL error-code value the name aliases.
76 value: ConditionValue,
77 /// Source location and node identity.
78 meta: Meta,
79 },
80 /// `DECLARE <name> CURSOR FOR <select>` — a cursor over a query.
81 Cursor {
82 /// The cursor name.
83 name: Ident,
84 /// The `SELECT` the cursor iterates; boxed to keep the variant small.
85 query: Box<Query<X>>,
86 /// Source location and node identity.
87 meta: Meta,
88 },
89 /// `DECLARE {CONTINUE | EXIT | UNDO} HANDLER FOR <condition> [, …] <statement>` — a
90 /// condition handler whose body runs when any listed condition is raised.
91 Handler {
92 /// The handler action (`CONTINUE`/`EXIT`/`UNDO`).
93 action: HandlerAction,
94 /// The condition values the handler catches, in source order (at least one).
95 conditions: ThinVec<HandlerCondition>,
96 /// The handler body — a single body statement (often a compound block); boxed
97 /// to keep the variant small.
98 body: Box<Statement<X>>,
99 /// Source location and node identity.
100 meta: Meta,
101 },
102}
103
104/// The action of a `DECLARE … HANDLER` — what happens after the handler body runs.
105///
106/// A tag (no `meta`): the keyword's span is subsumed by the enclosing
107/// [`Declaration::Handler`], exactly as [`super::TriggerTiming`] rides its parent's span.
108#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
109#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
110#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
111pub enum HandlerAction {
112 /// `CONTINUE` — resume execution after the statement that raised the condition.
113 Continue,
114 /// `EXIT` — leave the compound block the handler is declared in.
115 Exit,
116 /// `UNDO` — roll back and leave (parsed for completeness; the server restricts it).
117 Undo,
118}
119
120/// A condition value across the shared condition family: a `SQLSTATE` string, a MySQL
121/// error code, or a declared condition name.
122///
123/// The variant SET each parser produces is the grammar's subset for its site, not the whole
124/// enum: `DECLARE … CONDITION FOR` produces [`SqlState`](Self::SqlState) or
125/// [`ErrorCode`](Self::ErrorCode) (never a name — that form is a syntax error there), while
126/// `SIGNAL`/`RESIGNAL` produce [`SqlState`](Self::SqlState) or
127/// [`ConditionName`](Self::ConditionName) (a bare error code is a *syntax* error for
128/// `SIGNAL`, engine-measured `1064`). The type is the union so the two siblings share one
129/// vocabulary rather than minting parallel `SqlState` shapes.
130#[derive(Clone, Debug, PartialEq, Eq, Hash)]
131#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
132#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
133pub enum ConditionValue {
134 /// `SQLSTATE [VALUE] '<sqlstate>'` — a five-character SQLSTATE string constant.
135 SqlState {
136 /// Whether the optional `VALUE` noise keyword was written (fidelity tag).
137 value_keyword: bool,
138 /// The SQLSTATE string literal.
139 sqlstate: Literal,
140 /// Source location and node identity.
141 meta: Meta,
142 },
143 /// A bare MySQL error-code integer (e.g. `1051`). `DECLARE … CONDITION FOR` only; a
144 /// bare code is a syntax error in `SIGNAL`/`RESIGNAL`.
145 ErrorCode {
146 /// The error-code integer literal.
147 code: Literal,
148 /// Source location and node identity.
149 meta: Meta,
150 },
151 /// A condition name declared earlier in the block (`DECLARE … CONDITION`), signalled by
152 /// `SIGNAL <name>` / `RESIGNAL <name>`. Grammar-valid at top level (the sp-context
153 /// resolution restriction MySQL enforces — `1319` outside a stored program — is a
154 /// semantic check this parser leaves to name resolution, not a syntax reject).
155 ConditionName {
156 /// The referenced condition name.
157 name: Ident,
158 /// Source location and node identity.
159 meta: Meta,
160 },
161}
162
163/// One condition in a `DECLARE … HANDLER FOR <condition> [, …]` list.
164///
165/// A superset of [`ConditionValue`]: a handler additionally catches a condition name
166/// declared earlier in the block and the three general condition classes.
167#[derive(Clone, Debug, PartialEq, Eq, Hash)]
168#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
169#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
170pub enum HandlerCondition {
171 /// `SQLSTATE [VALUE] '<sqlstate>'` — a SQLSTATE string constant.
172 SqlState {
173 /// Whether the optional `VALUE` noise keyword was written (fidelity tag).
174 value_keyword: bool,
175 /// The SQLSTATE string literal.
176 sqlstate: Literal,
177 /// Source location and node identity.
178 meta: Meta,
179 },
180 /// A bare MySQL error-code integer (e.g. `1051`).
181 ErrorCode {
182 /// The error-code integer literal.
183 code: Literal,
184 /// Source location and node identity.
185 meta: Meta,
186 },
187 /// A condition name declared earlier in the block (`DECLARE … CONDITION`).
188 ConditionName {
189 /// The referenced condition name.
190 name: Ident,
191 /// Source location and node identity.
192 meta: Meta,
193 },
194 /// `SQLWARNING` — the class of `SQLSTATE` values beginning `01`.
195 SqlWarning {
196 /// Source location and node identity.
197 meta: Meta,
198 },
199 /// `NOT FOUND` — the class of `SQLSTATE` values beginning `02` (cursor exhaustion).
200 NotFound {
201 /// Source location and node identity.
202 meta: Meta,
203 },
204 /// `SQLEXCEPTION` — every remaining `SQLSTATE` class.
205 SqlException {
206 /// Source location and node identity.
207 meta: Meta,
208 },
209}
210
211/// An `IF <cond> THEN … [ELSEIF <cond> THEN …] … [ELSE …] END IF` statement.
212///
213/// The `IF` and each `ELSEIF` are folded into one ordered [`branches`](Self::branches)
214/// list (the first is the `IF`, the rest the `ELSEIF`s); the optional trailing `ELSE`
215/// body is [`else_body`](Self::else_body).
216#[derive(Clone, Debug, PartialEq, Eq, Hash)]
217#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
218#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
219pub struct IfStatement<X: Extension = NoExt> {
220 /// The `IF`/`ELSEIF` branches, in source order (always at least the `IF`).
221 pub branches: ThinVec<ConditionalBranch<X>>,
222 /// The optional `ELSE` body; `None` when no `ELSE` clause was written.
223 pub else_body: Option<ThinVec<Statement<X>>>,
224 /// Source location and node identity.
225 pub meta: Meta,
226}
227
228/// One `<cond> THEN <statements>` arm of an [`IfStatement`] or the WHEN arm of a
229/// searched [`CaseStatement`].
230#[derive(Clone, Debug, PartialEq, Eq, Hash)]
231#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
232#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
233pub struct ConditionalBranch<X: Extension = NoExt> {
234 /// The branch guard — the `IF`/`ELSEIF`/`WHEN` expression.
235 pub guard: Expr<X>,
236 /// The branch body, in source order.
237 pub body: ThinVec<Statement<X>>,
238 /// Source location and node identity.
239 pub meta: Meta,
240}
241
242/// A `CASE … END CASE` statement, in either the simple or searched form.
243///
244/// [`operand`](Self::operand) distinguishes them: `Some` is the simple `CASE <operand>
245/// WHEN <value> …` (each branch guard is a value compared to the operand); `None` is
246/// the searched `CASE WHEN <condition> …` (each branch guard is a boolean predicate).
247#[derive(Clone, Debug, PartialEq, Eq, Hash)]
248#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
249#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
250pub struct CaseStatement<X: Extension = NoExt> {
251 /// The simple-`CASE` operand; `None` for the searched form. Boxed to keep the
252 /// node small.
253 pub operand: Option<Box<Expr<X>>>,
254 /// The `WHEN … THEN …` branches, in source order (always at least one).
255 pub when_branches: ThinVec<ConditionalBranch<X>>,
256 /// The optional `ELSE` body; `None` when no `ELSE` clause was written.
257 pub else_body: Option<ThinVec<Statement<X>>>,
258 /// Source location and node identity.
259 pub meta: Meta,
260}
261
262/// A `[<label>:] LOOP … END LOOP [<label>]` unconditional loop.
263#[derive(Clone, Debug, PartialEq, Eq, Hash)]
264#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
265#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
266pub struct LoopStatement<X: Extension = NoExt> {
267 /// The opening loop label; `None` when unlabelled.
268 pub label: Option<Ident>,
269 /// The loop body, in source order.
270 pub body: ThinVec<Statement<X>>,
271 /// The closing `END LOOP <label>`; `None` when the close is bare.
272 pub end_label: Option<Ident>,
273 /// Source location and node identity.
274 pub meta: Meta,
275}
276
277/// A `[<label>:] WHILE <cond> DO … END WHILE [<label>]` pre-tested loop.
278#[derive(Clone, Debug, PartialEq, Eq, Hash)]
279#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
280#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
281pub struct WhileStatement<X: Extension = NoExt> {
282 /// The opening loop label; `None` when unlabelled.
283 pub label: Option<Ident>,
284 /// The `WHILE` continuation condition; boxed to keep the node small.
285 pub condition: Box<Expr<X>>,
286 /// The loop body, in source order.
287 pub body: ThinVec<Statement<X>>,
288 /// The closing `END WHILE <label>`; `None` when the close is bare.
289 pub end_label: Option<Ident>,
290 /// Source location and node identity.
291 pub meta: Meta,
292}
293
294/// A `[<label>:] REPEAT … UNTIL <cond> END REPEAT [<label>]` post-tested loop.
295#[derive(Clone, Debug, PartialEq, Eq, Hash)]
296#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
297#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
298pub struct RepeatStatement<X: Extension = NoExt> {
299 /// The opening loop label; `None` when unlabelled.
300 pub label: Option<Ident>,
301 /// The loop body, in source order.
302 pub body: ThinVec<Statement<X>>,
303 /// The `UNTIL` termination condition (tested after each pass); boxed to keep the
304 /// node small.
305 pub condition: Box<Expr<X>>,
306 /// The closing `END REPEAT <label>`; `None` when the close is bare.
307 pub end_label: Option<Ident>,
308 /// Source location and node identity.
309 pub meta: Meta,
310}
311
312/// A `LEAVE <label>` statement — leave the labelled block or loop.
313#[derive(Clone, Debug, PartialEq, Eq, Hash)]
314#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
315#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
316pub struct LeaveStatement {
317 /// The target label.
318 pub label: Ident,
319 /// Source location and node identity.
320 pub meta: Meta,
321}
322
323/// An `ITERATE <label>` statement — restart the labelled loop.
324#[derive(Clone, Debug, PartialEq, Eq, Hash)]
325#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
326#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
327pub struct IterateStatement {
328 /// The target loop label.
329 pub label: Ident,
330 /// Source location and node identity.
331 pub meta: Meta,
332}
333
334/// A `RETURN <expr>` statement — return a value from a stored function.
335///
336/// Function-only in the server (`RETURN` in a procedure is rejected); the node lands
337/// here and the routine family enforces the context.
338#[derive(Clone, Debug, PartialEq, Eq, Hash)]
339#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
340#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
341pub struct ReturnStatement<X: Extension = NoExt> {
342 /// The returned value expression.
343 pub value: Expr<X>,
344 /// Source location and node identity.
345 pub meta: Meta,
346}
347
348/// An `OPEN <cursor>` statement — open a declared cursor.
349#[derive(Clone, Debug, PartialEq, Eq, Hash)]
350#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
351#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
352pub struct OpenCursorStatement {
353 /// The cursor name.
354 pub cursor: Ident,
355 /// Source location and node identity.
356 pub meta: Meta,
357}
358
359/// A `CLOSE <cursor>` statement — close an open cursor.
360#[derive(Clone, Debug, PartialEq, Eq, Hash)]
361#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
362#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
363pub struct CloseCursorStatement {
364 /// The cursor name.
365 pub cursor: Ident,
366 /// Source location and node identity.
367 pub meta: Meta,
368}
369
370/// A `FETCH [[NEXT] FROM] <cursor> INTO <var> [, …]` statement — fetch the next row
371/// into local variables.
372#[derive(Clone, Debug, PartialEq, Eq, Hash)]
373#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
374#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
375pub struct FetchCursorStatement {
376 /// Whether the optional `NEXT` noise keyword was written (fidelity tag; `NEXT`
377 /// implies `FROM`).
378 pub next_keyword: bool,
379 /// Whether the optional `FROM` noise keyword was written (fidelity tag).
380 pub from_keyword: bool,
381 /// The cursor name.
382 pub cursor: Ident,
383 /// The `INTO` target variables, in source order (always at least one).
384 pub targets: ThinVec<Ident>,
385 /// Source location and node identity.
386 pub meta: Meta,
387}
388
389/// A `SIGNAL`/`RESIGNAL` statement: raise (or re-raise) a condition, optionally amending
390/// the diagnostics area with a `SET` item list.
391///
392/// One payload for both keywords (the enclosing [`Statement::Signal`]/[`Statement::Resignal`]
393/// records which): they share the grammar bar one difference the parser enforces — `SIGNAL`
394/// requires a [`condition`](Self::condition), `RESIGNAL` leaves it optional (re-raise the
395/// current condition, so a bare `RESIGNAL` and `RESIGNAL SET …` are both legal).
396#[derive(Clone, Debug, PartialEq, Eq, Hash)]
397#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
398#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
399pub struct SignalStatement<X: Extension = NoExt> {
400 /// The signalled condition — a `SQLSTATE '…'` or a declared condition name. Mandatory
401 /// for `SIGNAL` (parser-enforced), optional for `RESIGNAL`.
402 pub condition: Option<ConditionValue>,
403 /// The `SET <item> = <expr> [, …]` amendments; empty when no `SET` clause was written.
404 pub set_items: ThinVec<SignalItem<X>>,
405 /// Source location and node identity.
406 pub meta: Meta,
407}
408
409/// One `<name> = <expr>` amendment in a `SIGNAL`/`RESIGNAL` `SET` list.
410#[derive(Clone, Debug, PartialEq, Eq, Hash)]
411#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
412#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
413pub struct SignalItem<X: Extension = NoExt> {
414 /// Which diagnostics-area field is being set.
415 pub name: SignalItemName,
416 /// The value expression assigned to the field.
417 pub value: Expr<X>,
418 /// Source location and node identity.
419 pub meta: Meta,
420}
421
422/// The settable condition-information item name in a `SIGNAL`/`RESIGNAL` `SET` list.
423///
424/// A closed keyword set (a tag, no `meta` — the span is the enclosing [`SignalItem`]'s). The
425/// signal-settable subset deliberately EXCLUDES `RETURNED_SQLSTATE` (readable via
426/// `GET DIAGNOSTICS` but not signal-settable), so it is a distinct enum from
427/// [`ConditionInfoItemName`], not a shared one.
428#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
429#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
430#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
431pub enum SignalItemName {
432 /// `CLASS_ORIGIN`.
433 ClassOrigin,
434 /// `SUBCLASS_ORIGIN`.
435 SubclassOrigin,
436 /// `CONSTRAINT_CATALOG`.
437 ConstraintCatalog,
438 /// `CONSTRAINT_SCHEMA`.
439 ConstraintSchema,
440 /// `CONSTRAINT_NAME`.
441 ConstraintName,
442 /// `CATALOG_NAME`.
443 CatalogName,
444 /// `SCHEMA_NAME`.
445 SchemaName,
446 /// `TABLE_NAME`.
447 TableName,
448 /// `COLUMN_NAME`.
449 ColumnName,
450 /// `CURSOR_NAME`.
451 CursorName,
452 /// `MESSAGE_TEXT`.
453 MessageText,
454 /// `MYSQL_ERRNO`.
455 MysqlErrno,
456}
457
458/// A `GET [CURRENT | STACKED] DIAGNOSTICS …` statement — read the diagnostics area into
459/// target variables.
460#[derive(Clone, Debug, PartialEq, Eq, Hash)]
461#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
462#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
463pub struct GetDiagnosticsStatement<X: Extension = NoExt> {
464 /// Which diagnostics area (the `CURRENT`/`STACKED` keyword, or none — implicit current).
465 pub area: DiagnosticsArea,
466 /// The requested information: statement-level items or a single condition's items.
467 pub info: DiagnosticsInfo<X>,
468 /// Source location and node identity.
469 pub meta: Meta,
470}
471
472/// The `which_area` written before `DIAGNOSTICS`. A tag: `None` and `Current` name the same
473/// area and differ only in spelling (a fidelity distinction so both round-trip).
474#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
475#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
476#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
477pub enum DiagnosticsArea {
478 /// No area keyword — the implicit current area.
479 Implicit,
480 /// Explicit `CURRENT`.
481 Current,
482 /// Explicit `STACKED`.
483 Stacked,
484}
485
486/// The information a `GET DIAGNOSTICS` requests: statement-level items, or a single
487/// condition's items keyed by a `CONDITION <number>` selector.
488#[derive(Clone, Debug, PartialEq, Eq, Hash)]
489#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
490#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
491pub enum DiagnosticsInfo<X: Extension = NoExt> {
492 /// `<target> = {NUMBER | ROW_COUNT} [, …]` — the statement-level diagnostics items.
493 Statement {
494 /// The requested statement items, in source order (always at least one).
495 items: ThinVec<StatementInfoItem<X>>,
496 /// Source location and node identity.
497 meta: Meta,
498 },
499 /// `CONDITION <number> <target> = <cond-item> [, …]` — one condition's items.
500 Condition {
501 /// The `CONDITION <number>` selector expression (a limited expr subset).
502 number: Box<Expr<X>>,
503 /// The requested condition items, in source order (always at least one).
504 items: ThinVec<ConditionInfoItem<X>>,
505 /// Source location and node identity.
506 meta: Meta,
507 },
508}
509
510/// One `<target> = {NUMBER | ROW_COUNT}` item in a `GET DIAGNOSTICS` statement-information
511/// list.
512#[derive(Clone, Debug, PartialEq, Eq, Hash)]
513#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
514#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
515pub struct StatementInfoItem<X: Extension = NoExt> {
516 /// The target lvalue receiving the value (a `@user` variable or a local variable name).
517 pub target: Expr<X>,
518 /// Which statement-level field is read.
519 pub name: StatementInfoItemName,
520 /// Source location and node identity.
521 pub meta: Meta,
522}
523
524/// The readable statement-level diagnostics item name (a tag, no `meta`).
525#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
526#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
527#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
528pub enum StatementInfoItemName {
529 /// `NUMBER` — the count of conditions in the diagnostics area.
530 Number,
531 /// `ROW_COUNT` — the affected-row count of the previous statement.
532 RowCount,
533}
534
535/// One `<target> = <cond-item>` item in a `GET DIAGNOSTICS CONDITION` list.
536#[derive(Clone, Debug, PartialEq, Eq, Hash)]
537#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
538#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
539pub struct ConditionInfoItem<X: Extension = NoExt> {
540 /// The target lvalue receiving the value (a `@user` variable or a local variable name).
541 pub target: Expr<X>,
542 /// Which condition-level field is read.
543 pub name: ConditionInfoItemName,
544 /// Source location and node identity.
545 pub meta: Meta,
546}
547
548/// The readable condition-level diagnostics item name (a tag, no `meta`).
549///
550/// A superset of [`SignalItemName`]: every signal-settable field plus `RETURNED_SQLSTATE`,
551/// which is readable here but not signal-settable — the two lists are intentionally
552/// asymmetric, so they are distinct enums.
553#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
554#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
555#[cfg_attr(feature = "serde-deserialize", derive(serde::Deserialize))]
556pub enum ConditionInfoItemName {
557 /// `CLASS_ORIGIN`.
558 ClassOrigin,
559 /// `SUBCLASS_ORIGIN`.
560 SubclassOrigin,
561 /// `CONSTRAINT_CATALOG`.
562 ConstraintCatalog,
563 /// `CONSTRAINT_SCHEMA`.
564 ConstraintSchema,
565 /// `CONSTRAINT_NAME`.
566 ConstraintName,
567 /// `CATALOG_NAME`.
568 CatalogName,
569 /// `SCHEMA_NAME`.
570 SchemaName,
571 /// `TABLE_NAME`.
572 TableName,
573 /// `COLUMN_NAME`.
574 ColumnName,
575 /// `CURSOR_NAME`.
576 CursorName,
577 /// `MESSAGE_TEXT`.
578 MessageText,
579 /// `MYSQL_ERRNO`.
580 MysqlErrno,
581 /// `RETURNED_SQLSTATE` — readable only (not signal-settable).
582 ReturnedSqlstate,
583}