Skip to main content

icydb_diagnostic_code/
lib.rs

1//! Compact diagnostic identity for IcyDB.
2//!
3//! This crate intentionally contains no rich diagnostic prose or Candid wire
4//! types. Production canister builds collapse diagnostics to numeric wire
5//! codes before they cross the public canister boundary.
6
7///
8/// DiagnosticCode
9///
10/// Stable machine-readable diagnostic reason.
11///
12
13#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
14pub enum DiagnosticCode {
15    QueryValidate,
16    QueryIntent,
17    QueryPlan,
18    QueryAccessRequirement,
19    QueryUnorderedPagination,
20    QueryInvalidContinuationCursor,
21    QueryNotFound,
22    QueryNotUnique,
23    QueryNumericOverflow,
24    QueryNumericNotRepresentable,
25    QueryUnsupportedSqlFeature,
26    QuerySqlSurfaceMismatch,
27    SchemaDdlAdmission,
28    StoreNotFound,
29    StoreCorruption,
30    StoreInvariantViolation,
31    RuntimeCorruption,
32    RuntimeIncompatiblePersistedFormat,
33    RuntimeInvariantViolation,
34    RuntimeConflict,
35    RuntimeNotFound,
36    RuntimeUnsupported,
37    RuntimeInternal,
38}
39
40impl DiagnosticCode {
41    /// Return the broad diagnostic class for this code.
42    #[must_use]
43    pub const fn class(self) -> ErrorClass {
44        match self {
45            Self::StoreCorruption | Self::RuntimeCorruption => ErrorClass::Corruption,
46            Self::RuntimeIncompatiblePersistedFormat => ErrorClass::IncompatiblePersistedFormat,
47            Self::QueryNotFound | Self::StoreNotFound | Self::RuntimeNotFound => {
48                ErrorClass::NotFound
49            }
50            Self::RuntimeConflict => ErrorClass::Conflict,
51            Self::QueryUnsupportedSqlFeature
52            | Self::QuerySqlSurfaceMismatch
53            | Self::RuntimeUnsupported => ErrorClass::Unsupported,
54            Self::StoreInvariantViolation | Self::RuntimeInvariantViolation => {
55                ErrorClass::InvariantViolation
56            }
57            Self::RuntimeInternal => ErrorClass::Internal,
58            Self::QueryValidate
59            | Self::QueryIntent
60            | Self::QueryPlan
61            | Self::QueryAccessRequirement
62            | Self::QueryUnorderedPagination
63            | Self::QueryInvalidContinuationCursor
64            | Self::QueryNotUnique
65            | Self::QueryNumericOverflow
66            | Self::QueryNumericNotRepresentable
67            | Self::SchemaDdlAdmission => ErrorClass::Query,
68        }
69    }
70
71    /// Return the default diagnostic origin for this code.
72    #[must_use]
73    pub const fn origin(self) -> ErrorOrigin {
74        match self {
75            Self::StoreNotFound | Self::StoreCorruption | Self::StoreInvariantViolation => {
76                ErrorOrigin::Store
77            }
78            Self::RuntimeCorruption
79            | Self::RuntimeIncompatiblePersistedFormat
80            | Self::RuntimeInvariantViolation
81            | Self::RuntimeConflict
82            | Self::RuntimeNotFound
83            | Self::RuntimeUnsupported
84            | Self::RuntimeInternal => ErrorOrigin::Runtime,
85            Self::QueryValidate
86            | Self::QueryIntent
87            | Self::QueryPlan
88            | Self::QueryAccessRequirement
89            | Self::QueryUnorderedPagination
90            | Self::QueryInvalidContinuationCursor
91            | Self::QueryNotFound
92            | Self::QueryNotUnique
93            | Self::QueryNumericOverflow
94            | Self::QueryNumericNotRepresentable
95            | Self::QueryUnsupportedSqlFeature
96            | Self::QuerySqlSurfaceMismatch
97            | Self::SchemaDdlAdmission => ErrorOrigin::Query,
98        }
99    }
100
101    /// Return the compact public wire code for this broad diagnostic reason.
102    #[must_use]
103    pub const fn error_code(self) -> ErrorCode {
104        match self {
105            Self::QueryValidate => ErrorCode::QUERY_VALIDATE,
106            Self::QueryIntent => ErrorCode::QUERY_INTENT,
107            Self::QueryPlan => ErrorCode::QUERY_PLAN,
108            Self::QueryAccessRequirement => ErrorCode::QUERY_ACCESS_REQUIREMENT,
109            Self::QueryUnorderedPagination => ErrorCode::QUERY_UNORDERED_PAGINATION,
110            Self::QueryInvalidContinuationCursor => ErrorCode::QUERY_INVALID_CONTINUATION_CURSOR,
111            Self::QueryNotFound => ErrorCode::QUERY_NOT_FOUND,
112            Self::QueryNotUnique => ErrorCode::QUERY_NOT_UNIQUE,
113            Self::QueryNumericOverflow => ErrorCode::QUERY_NUMERIC_OVERFLOW,
114            Self::QueryNumericNotRepresentable => ErrorCode::QUERY_NUMERIC_NOT_REPRESENTABLE,
115            Self::QueryUnsupportedSqlFeature => ErrorCode::QUERY_UNSUPPORTED_SQL_FEATURE,
116            Self::QuerySqlSurfaceMismatch => ErrorCode::QUERY_SQL_SURFACE_MISMATCH,
117            Self::SchemaDdlAdmission => ErrorCode::SCHEMA_DDL_ADMISSION,
118            Self::StoreNotFound => ErrorCode::STORE_NOT_FOUND,
119            Self::StoreCorruption => ErrorCode::STORE_CORRUPTION,
120            Self::StoreInvariantViolation => ErrorCode::STORE_INVARIANT_VIOLATION,
121            Self::RuntimeCorruption => ErrorCode::RUNTIME_CORRUPTION,
122            Self::RuntimeIncompatiblePersistedFormat => {
123                ErrorCode::RUNTIME_INCOMPATIBLE_PERSISTED_FORMAT
124            }
125            Self::RuntimeInvariantViolation => ErrorCode::RUNTIME_INVARIANT_VIOLATION,
126            Self::RuntimeConflict => ErrorCode::RUNTIME_CONFLICT,
127            Self::RuntimeNotFound => ErrorCode::RUNTIME_NOT_FOUND,
128            Self::RuntimeUnsupported => ErrorCode::RUNTIME_UNSUPPORTED,
129            Self::RuntimeInternal => ErrorCode::RUNTIME_INTERNAL,
130        }
131    }
132}
133
134///
135/// ErrorCode
136///
137/// Stable numeric public error identity.
138///
139/// The public Candid `icydb::Error` stores this value as `nat16` so canister
140/// interfaces do not retain rich diagnostic enum labels. Rich diagnostics can
141/// still be reconstructed by host-side tooling from this leaf code. Before
142/// 1.0.0, the code space is hard-cut to a single compact sequential range.
143///
144
145#[derive(Clone, Copy, Eq, Hash, PartialEq)]
146pub struct ErrorCode(u16);
147
148impl ErrorCode {
149    pub const QUERY_VALIDATE: Self = Self(1);
150    pub const QUERY_INTENT: Self = Self(2);
151    pub const QUERY_PLAN: Self = Self(3);
152    pub const QUERY_ACCESS_REQUIREMENT: Self = Self(4);
153    pub const QUERY_UNORDERED_PAGINATION: Self = Self(5);
154    pub const QUERY_INVALID_CONTINUATION_CURSOR: Self = Self(6);
155    pub const QUERY_NOT_FOUND: Self = Self(7);
156    pub const QUERY_NOT_UNIQUE: Self = Self(8);
157    pub const QUERY_NUMERIC_OVERFLOW: Self = Self(9);
158    pub const QUERY_NUMERIC_NOT_REPRESENTABLE: Self = Self(10);
159    pub const QUERY_UNSUPPORTED_SQL_FEATURE: Self = Self(11);
160    pub const QUERY_SQL_SURFACE_MISMATCH: Self = Self(12);
161    pub const SCHEMA_DDL_ADMISSION: Self = Self(13);
162    pub const STORE_NOT_FOUND: Self = Self(14);
163    pub const STORE_CORRUPTION: Self = Self(15);
164    pub const STORE_INVARIANT_VIOLATION: Self = Self(16);
165    pub const RUNTIME_CORRUPTION: Self = Self(17);
166    pub const RUNTIME_INCOMPATIBLE_PERSISTED_FORMAT: Self = Self(18);
167    pub const RUNTIME_INVARIANT_VIOLATION: Self = Self(19);
168    pub const RUNTIME_CONFLICT: Self = Self(20);
169    pub const RUNTIME_NOT_FOUND: Self = Self(21);
170    pub const RUNTIME_UNSUPPORTED: Self = Self(22);
171    pub const RUNTIME_INTERNAL: Self = Self(23);
172
173    pub const RUNTIME_BOUNDARY_SQL_SURFACE_CONTROLLER_REQUIRED: Self = Self(24);
174    pub const RUNTIME_BOUNDARY_SCHEMA_SURFACE_CONTROLLER_REQUIRED: Self = Self(25);
175    pub const RUNTIME_BOUNDARY_SQL_QUERY_NO_CONFIGURED_ENTITIES: Self = Self(26);
176    pub const RUNTIME_BOUNDARY_SQL_QUERY_ENTITY_NOT_CONFIGURED: Self = Self(27);
177    pub const RUNTIME_BOUNDARY_SQL_DDL_TARGET_REQUIRED: Self = Self(28);
178    pub const RUNTIME_BOUNDARY_SQL_DDL_ENTITY_NOT_CONFIGURED: Self = Self(29);
179    pub const RUNTIME_BOUNDARY_QUERY_RESPONSE_ROWS_REQUIRED: Self = Self(30);
180    pub const RUNTIME_BOUNDARY_QUERY_RESPONSE_GROUPED_ROWS_REQUIRED: Self = Self(31);
181    pub const RUNTIME_BOUNDARY_MUTATION_RESULT_ENTITY_REQUIRED: Self = Self(32);
182    pub const RUNTIME_BOUNDARY_MUTATION_RESULT_ENTITIES_REQUIRED: Self = Self(33);
183    pub const RUNTIME_BOUNDARY_MUTATION_RESULT_ID_REQUIRED: Self = Self(34);
184    pub const RUNTIME_BOUNDARY_MUTATION_RESULT_IDS_REQUIRED: Self = Self(35);
185    pub const RUNTIME_BOUNDARY_ROW_PROJECTION_FIELD_NOT_CONFIGURED: Self = Self(36);
186
187    pub const SQL_FEATURE_AGGREGATE_FILTER_CLAUSE: Self = Self(37);
188    pub const SQL_FEATURE_ALTER_STATEMENT_BEYOND_ALTER_TABLE: Self = Self(38);
189    pub const SQL_FEATURE_ALTER_TABLE_ADD_COLUMN_DUPLICATE_DEFAULT: Self = Self(39);
190    pub const SQL_FEATURE_ALTER_TABLE_ADD_COLUMN_MODIFIERS: Self = Self(40);
191    pub const SQL_FEATURE_ALTER_TABLE_ADD_STATEMENT_BEYOND_ADD_COLUMN: Self = Self(41);
192    pub const SQL_FEATURE_ALTER_TABLE_ALTER_COLUMN_DROP_UNSUPPORTED_ACTION: Self = Self(42);
193    pub const SQL_FEATURE_ALTER_TABLE_ALTER_COLUMN_MODIFIERS: Self = Self(43);
194    pub const SQL_FEATURE_ALTER_TABLE_ALTER_COLUMN_SET_UNSUPPORTED_ACTION: Self = Self(44);
195    pub const SQL_FEATURE_ALTER_TABLE_ALTER_COLUMN_UNSUPPORTED_ACTION: Self = Self(45);
196    pub const SQL_FEATURE_ALTER_TABLE_ALTER_STATEMENT_BEYOND_ALTER_COLUMN: Self = Self(46);
197    pub const SQL_FEATURE_ALTER_TABLE_DROP_COLUMN_IF_EXISTS_SYNTAX: Self = Self(47);
198    pub const SQL_FEATURE_ALTER_TABLE_DROP_COLUMN_MODIFIERS: Self = Self(48);
199    pub const SQL_FEATURE_ALTER_TABLE_DROP_STATEMENT_BEYOND_DROP_COLUMN: Self = Self(49);
200    pub const SQL_FEATURE_ALTER_TABLE_RENAME_COLUMN_MISSING_TO: Self = Self(50);
201    pub const SQL_FEATURE_ALTER_TABLE_RENAME_COLUMN_MODIFIERS: Self = Self(51);
202    pub const SQL_FEATURE_ALTER_TABLE_RENAME_STATEMENT_BEYOND_RENAME_COLUMN: Self = Self(52);
203    pub const SQL_FEATURE_ALTER_TABLE_UNSUPPORTED_OPERATION: Self = Self(53);
204    pub const SQL_FEATURE_COLUMN_ALIAS: Self = Self(54);
205    pub const SQL_FEATURE_CREATE_INDEX_IF_NOT_EXISTS_SYNTAX: Self = Self(55);
206    pub const SQL_FEATURE_CREATE_INDEX_KEY_ORDERING_MODIFIERS: Self = Self(56);
207    pub const SQL_FEATURE_CREATE_INDEX_MODIFIERS: Self = Self(57);
208    pub const SQL_FEATURE_CREATE_STATEMENT_BEYOND_CREATE_INDEX: Self = Self(58);
209    pub const SQL_FEATURE_DESCRIBE_MODIFIER: Self = Self(59);
210    pub const SQL_FEATURE_DDL_SCHEMA_VERSION_DUPLICATE_EXPECTED_CLAUSE: Self = Self(60);
211    pub const SQL_FEATURE_DDL_SCHEMA_VERSION_DUPLICATE_SET_CLAUSE: Self = Self(61);
212    pub const SQL_FEATURE_DROP_INDEX_MODIFIERS: Self = Self(62);
213    pub const SQL_FEATURE_DROP_INDEX_IF_EXISTS_SYNTAX: Self = Self(63);
214    pub const SQL_FEATURE_DROP_STATEMENT_BEYOND_DROP_INDEX: Self = Self(64);
215    pub const SQL_FEATURE_EXPRESSION_INDEX_UNSUPPORTED_FUNCTION: Self = Self(65);
216    pub const SQL_FEATURE_HAVING: Self = Self(66);
217    pub const SQL_FEATURE_INSERT: Self = Self(67);
218    pub const SQL_FEATURE_JOIN: Self = Self(68);
219    pub const SQL_FEATURE_LIKE_PATTERN_BEYOND_TRAILING_PREFIX: Self = Self(69);
220    pub const SQL_FEATURE_LOWER_FIELD_PREDICATE_UNSUPPORTED: Self = Self(70);
221    pub const SQL_FEATURE_MULTI_STATEMENT_SQL: Self = Self(71);
222    pub const SQL_FEATURE_NESTED_AGGREGATE_INPUT: Self = Self(72);
223    pub const SQL_FEATURE_NESTED_PROJECTION_FUNCTION_IN_ARITHMETIC: Self = Self(73);
224    pub const SQL_FEATURE_ORDER_BY_UNSUPPORTED_FORM: Self = Self(74);
225    pub const SQL_FEATURE_OTHER: Self = Self(75);
226    pub const SQL_FEATURE_PARAMETER_BINDING: Self = Self(76);
227    pub const SQL_FEATURE_PARAMETERIZED_SCHEMA_VERSION: Self = Self(77);
228    pub const SQL_FEATURE_PREDICATE_STARTS_WITH_FIRST_ARGUMENT: Self = Self(78);
229    pub const SQL_FEATURE_QUOTED_IDENTIFIERS: Self = Self(79);
230    pub const SQL_FEATURE_RETURNING_UNSUPPORTED_SHAPE: Self = Self(80);
231    pub const SQL_FEATURE_SCALAR_FUNCTION_EXPRESSION_POSITION: Self = Self(81);
232    pub const SQL_FEATURE_SCALE_TAKING_NUMERIC_FUNCTION_EXPRESSION_POSITION: Self = Self(82);
233    pub const SQL_FEATURE_SEARCHED_CASE_GROUPED_ORDER_BY: Self = Self(83);
234    pub const SQL_FEATURE_SHOW_COLUMNS_MODIFIERS: Self = Self(84);
235    pub const SQL_FEATURE_SHOW_ENTITIES_MODIFIERS: Self = Self(85);
236    pub const SQL_FEATURE_SHOW_INDEXES_MODIFIERS: Self = Self(86);
237    pub const SQL_FEATURE_SHOW_MEMORY_MODIFIERS: Self = Self(87);
238    pub const SQL_FEATURE_SHOW_STORES_MODIFIERS: Self = Self(88);
239    pub const SQL_FEATURE_SHOW_UNSUPPORTED_COMMAND: Self = Self(89);
240    pub const SQL_FEATURE_SIMPLE_CASE_EXPRESSION: Self = Self(90);
241    pub const SQL_FEATURE_STANDALONE_LITERAL_PROJECTION_ITEM: Self = Self(91);
242    pub const SQL_FEATURE_SUPPORTED_GROUPED_ORDER_BY_EXPRESSION_FAMILY: Self = Self(92);
243    pub const SQL_FEATURE_SUPPORTED_ORDER_BY_EXPRESSION_FAMILY: Self = Self(93);
244    pub const SQL_FEATURE_UNION_INTERSECT_EXCEPT: Self = Self(94);
245    pub const SQL_FEATURE_UNSUPPORTED_FUNCTION_NAMESPACE: Self = Self(95);
246    pub const SQL_FEATURE_UPDATE: Self = Self(96);
247    pub const SQL_FEATURE_UPPER_FIELD_PREDICATE_UNSUPPORTED: Self = Self(97);
248    pub const SQL_FEATURE_WINDOW_FUNCTION: Self = Self(98);
249    pub const SQL_FEATURE_WITH: Self = Self(99);
250
251    const SQL_FEATURE_DETAILS: [SqlFeatureCode; 63] = [
252        SqlFeatureCode::AggregateFilterClause,
253        SqlFeatureCode::AlterStatementBeyondAlterTable,
254        SqlFeatureCode::AlterTableAddColumnDuplicateDefault,
255        SqlFeatureCode::AlterTableAddColumnModifiers,
256        SqlFeatureCode::AlterTableAddStatementBeyondAddColumn,
257        SqlFeatureCode::AlterTableAlterColumnDropUnsupportedAction,
258        SqlFeatureCode::AlterTableAlterColumnModifiers,
259        SqlFeatureCode::AlterTableAlterColumnSetUnsupportedAction,
260        SqlFeatureCode::AlterTableAlterColumnUnsupportedAction,
261        SqlFeatureCode::AlterTableAlterStatementBeyondAlterColumn,
262        SqlFeatureCode::AlterTableDropColumnIfExistsSyntax,
263        SqlFeatureCode::AlterTableDropColumnModifiers,
264        SqlFeatureCode::AlterTableDropStatementBeyondDropColumn,
265        SqlFeatureCode::AlterTableRenameColumnMissingTo,
266        SqlFeatureCode::AlterTableRenameColumnModifiers,
267        SqlFeatureCode::AlterTableRenameStatementBeyondRenameColumn,
268        SqlFeatureCode::AlterTableUnsupportedOperation,
269        SqlFeatureCode::ColumnAlias,
270        SqlFeatureCode::CreateIndexIfNotExistsSyntax,
271        SqlFeatureCode::CreateIndexKeyOrderingModifiers,
272        SqlFeatureCode::CreateIndexModifiers,
273        SqlFeatureCode::CreateStatementBeyondCreateIndex,
274        SqlFeatureCode::DescribeModifier,
275        SqlFeatureCode::DdlSchemaVersionDuplicateExpectedClause,
276        SqlFeatureCode::DdlSchemaVersionDuplicateSetClause,
277        SqlFeatureCode::DropIndexModifiers,
278        SqlFeatureCode::DropIndexIfExistsSyntax,
279        SqlFeatureCode::DropStatementBeyondDropIndex,
280        SqlFeatureCode::ExpressionIndexUnsupportedFunction,
281        SqlFeatureCode::Having,
282        SqlFeatureCode::Insert,
283        SqlFeatureCode::Join,
284        SqlFeatureCode::LikePatternBeyondTrailingPrefix,
285        SqlFeatureCode::LowerFieldPredicateUnsupported,
286        SqlFeatureCode::MultiStatementSql,
287        SqlFeatureCode::NestedAggregateInput,
288        SqlFeatureCode::NestedProjectionFunctionInArithmetic,
289        SqlFeatureCode::OrderByUnsupportedForm,
290        SqlFeatureCode::Other,
291        SqlFeatureCode::ParameterBinding,
292        SqlFeatureCode::ParameterizedSchemaVersion,
293        SqlFeatureCode::PredicateStartsWithFirstArgument,
294        SqlFeatureCode::QuotedIdentifiers,
295        SqlFeatureCode::ReturningUnsupportedShape,
296        SqlFeatureCode::ScalarFunctionExpressionPosition,
297        SqlFeatureCode::ScaleTakingNumericFunctionExpressionPosition,
298        SqlFeatureCode::SearchedCaseGroupedOrderBy,
299        SqlFeatureCode::ShowColumnsModifiers,
300        SqlFeatureCode::ShowEntitiesModifiers,
301        SqlFeatureCode::ShowIndexesModifiers,
302        SqlFeatureCode::ShowMemoryModifiers,
303        SqlFeatureCode::ShowStoresModifiers,
304        SqlFeatureCode::ShowUnsupportedCommand,
305        SqlFeatureCode::SimpleCaseExpression,
306        SqlFeatureCode::StandaloneLiteralProjectionItem,
307        SqlFeatureCode::SupportedGroupedOrderByExpressionFamily,
308        SqlFeatureCode::SupportedOrderByExpressionFamily,
309        SqlFeatureCode::UnionIntersectExcept,
310        SqlFeatureCode::UnsupportedFunctionNamespace,
311        SqlFeatureCode::Update,
312        SqlFeatureCode::UpperFieldPredicateUnsupported,
313        SqlFeatureCode::WindowFunction,
314        SqlFeatureCode::With,
315    ];
316
317    pub const SQL_SURFACE_QUERY_REJECTS_INSERT: Self = Self(100);
318    pub const SQL_SURFACE_QUERY_REJECTS_UPDATE: Self = Self(101);
319    pub const SQL_SURFACE_QUERY_REJECTS_DELETE: Self = Self(102);
320    pub const SQL_SURFACE_UPDATE_REJECTS_SELECT: Self = Self(103);
321    pub const SQL_SURFACE_UPDATE_REJECTS_EXPLAIN: Self = Self(104);
322    pub const SQL_SURFACE_UPDATE_REJECTS_DESCRIBE: Self = Self(105);
323    pub const SQL_SURFACE_UPDATE_REJECTS_SHOW_INDEXES: Self = Self(106);
324    pub const SQL_SURFACE_UPDATE_REJECTS_SHOW_COLUMNS: Self = Self(107);
325    pub const SQL_SURFACE_UPDATE_REJECTS_SHOW_ENTITIES: Self = Self(108);
326    pub const SQL_SURFACE_UPDATE_REJECTS_SHOW_STORES: Self = Self(109);
327    pub const SQL_SURFACE_UPDATE_REJECTS_SHOW_MEMORY: Self = Self(110);
328
329    pub const SCHEMA_DDL_MISSING_EXPECTED_SCHEMA_VERSION: Self = Self(111);
330    pub const SCHEMA_DDL_MISSING_NEXT_SCHEMA_VERSION: Self = Self(112);
331    pub const SCHEMA_DDL_STALE_EXPECTED_SCHEMA_VERSION: Self = Self(113);
332    pub const SCHEMA_DDL_INVALID_EXPECTED_SCHEMA_VERSION: Self = Self(114);
333    pub const SCHEMA_DDL_INVALID_NEXT_SCHEMA_VERSION: Self = Self(115);
334    pub const SCHEMA_DDL_ACCEPTED_SCHEMA_CHANGE_WITHOUT_VERSION_BUMP: Self = Self(116);
335    pub const SCHEMA_DDL_EMPTY_VERSION_BUMP: Self = Self(117);
336    pub const SCHEMA_DDL_VERSION_GAP: Self = Self(118);
337    pub const SCHEMA_DDL_VERSION_ROLLBACK: Self = Self(119);
338    pub const SCHEMA_DDL_FINGERPRINT_METHOD_MISMATCH: Self = Self(120);
339    pub const SCHEMA_DDL_UNSUPPORTED_TRANSITION_CLASS: Self = Self(121);
340    pub const SCHEMA_DDL_PHYSICAL_RUNNER_MISSING: Self = Self(122);
341    pub const SCHEMA_DDL_VALIDATION_FAILED: Self = Self(123);
342    pub const SCHEMA_DDL_PUBLICATION_RACE_LOST: Self = Self(124);
343    pub const SCHEMA_DDL_INVALID_ADD_COLUMN_DEFAULT: Self = Self(125);
344    pub const SCHEMA_DDL_INVALID_ALTER_COLUMN_DEFAULT: Self = Self(126);
345    pub const SCHEMA_DDL_GENERATED_INDEX_DROP_REJECTED: Self = Self(127);
346    pub const SCHEMA_DDL_REQUIRED_DROP_DEFAULT_UNSUPPORTED: Self = Self(128);
347    pub const SCHEMA_DDL_GENERATED_FIELD_DEFAULT_CHANGE_REJECTED: Self = Self(129);
348    pub const SCHEMA_DDL_GENERATED_FIELD_NULLABILITY_CHANGE_REJECTED: Self = Self(130);
349    pub const SCHEMA_DDL_SET_NOT_NULL_VALIDATION_FAILED: Self = Self(131);
350
351    /// Build an error code from its raw public wire value.
352    #[must_use]
353    pub const fn from_raw(raw: u16) -> Self {
354        Self(raw)
355    }
356
357    /// Return the raw public wire value.
358    #[must_use]
359    pub const fn raw(self) -> u16 {
360        self.0
361    }
362
363    /// Collapse a rich diagnostic into one public leaf code.
364    #[must_use]
365    pub const fn from_parts(code: DiagnosticCode, detail: Option<DiagnosticDetail>) -> Self {
366        match detail {
367            Some(DiagnosticDetail::QueryKind { kind }) => Self::from_query_kind(kind),
368            Some(DiagnosticDetail::RuntimeKind { kind }) => Self::from_runtime_kind(kind),
369            Some(DiagnosticDetail::RuntimeBoundary { boundary }) => {
370                Self::from_runtime_boundary(boundary)
371            }
372            Some(DiagnosticDetail::SchemaDdlAdmission { reason }) => Self::from_schema_ddl(reason),
373            Some(DiagnosticDetail::UnsupportedSqlFeature { feature }) => {
374                Self::from_sql_feature(feature)
375            }
376            Some(DiagnosticDetail::SqlSurfaceMismatch { mismatch }) => {
377                Self::from_sql_surface_mismatch(mismatch)
378            }
379            None => code.error_code(),
380        }
381    }
382
383    /// Return the broad diagnostic reason represented by this public code.
384    #[must_use]
385    pub const fn diagnostic_code(self) -> DiagnosticCode {
386        match self.raw() {
387            1 => DiagnosticCode::QueryValidate,
388            2 => DiagnosticCode::QueryIntent,
389            3 => DiagnosticCode::QueryPlan,
390            4 => DiagnosticCode::QueryAccessRequirement,
391            5 => DiagnosticCode::QueryUnorderedPagination,
392            6 => DiagnosticCode::QueryInvalidContinuationCursor,
393            7 => DiagnosticCode::QueryNotFound,
394            8 => DiagnosticCode::QueryNotUnique,
395            9 => DiagnosticCode::QueryNumericOverflow,
396            10 => DiagnosticCode::QueryNumericNotRepresentable,
397            11 | 37..=99 => DiagnosticCode::QueryUnsupportedSqlFeature,
398            12 | 100..=110 => DiagnosticCode::QuerySqlSurfaceMismatch,
399            13 | 111..=131 => DiagnosticCode::SchemaDdlAdmission,
400            14 => DiagnosticCode::StoreNotFound,
401            15 => DiagnosticCode::StoreCorruption,
402            16 => DiagnosticCode::StoreInvariantViolation,
403            17 => DiagnosticCode::RuntimeCorruption,
404            18 => DiagnosticCode::RuntimeIncompatiblePersistedFormat,
405            19 => DiagnosticCode::RuntimeInvariantViolation,
406            20 => DiagnosticCode::RuntimeConflict,
407            21 => DiagnosticCode::RuntimeNotFound,
408            22 | 24..=36 => DiagnosticCode::RuntimeUnsupported,
409            _ => DiagnosticCode::RuntimeInternal,
410        }
411    }
412
413    /// Return the diagnostic class represented by this public code.
414    #[must_use]
415    pub const fn class(self) -> ErrorClass {
416        self.diagnostic_code().class()
417    }
418
419    /// Reconstruct rich diagnostic detail for host-side rendering, when known.
420    #[must_use]
421    pub const fn diagnostic_detail(self) -> Option<DiagnosticDetail> {
422        match self.raw() {
423            1..=8 => Self::query_kind_detail(self.raw()),
424            17..=23 => Self::runtime_kind_detail(self.raw()),
425            24..=36 => Self::runtime_boundary_detail(self.raw()),
426            37..=99 => Self::sql_feature_detail(self.raw()),
427            100..=110 => Self::sql_surface_detail(self.raw()),
428            111..=131 => Self::schema_ddl_detail(self.raw()),
429            _ => None,
430        }
431    }
432
433    /// Reconstruct a rich diagnostic payload for host-side rendering.
434    #[must_use]
435    pub const fn diagnostic(self, origin: ErrorOrigin) -> Diagnostic {
436        Diagnostic::new(self.diagnostic_code(), origin, self.diagnostic_detail())
437    }
438
439    const fn from_query_kind(kind: QueryErrorKind) -> Self {
440        match kind {
441            QueryErrorKind::Validate => Self::QUERY_VALIDATE,
442            QueryErrorKind::Intent => Self::QUERY_INTENT,
443            QueryErrorKind::Plan => Self::QUERY_PLAN,
444            QueryErrorKind::AccessRequirement => Self::QUERY_ACCESS_REQUIREMENT,
445            QueryErrorKind::UnorderedPagination => Self::QUERY_UNORDERED_PAGINATION,
446            QueryErrorKind::InvalidContinuationCursor => Self::QUERY_INVALID_CONTINUATION_CURSOR,
447            QueryErrorKind::NotFound => Self::QUERY_NOT_FOUND,
448            QueryErrorKind::NotUnique => Self::QUERY_NOT_UNIQUE,
449        }
450    }
451
452    const fn from_runtime_kind(kind: RuntimeErrorKind) -> Self {
453        match kind {
454            RuntimeErrorKind::Corruption => Self::RUNTIME_CORRUPTION,
455            RuntimeErrorKind::IncompatiblePersistedFormat => {
456                Self::RUNTIME_INCOMPATIBLE_PERSISTED_FORMAT
457            }
458            RuntimeErrorKind::InvariantViolation => Self::RUNTIME_INVARIANT_VIOLATION,
459            RuntimeErrorKind::Conflict => Self::RUNTIME_CONFLICT,
460            RuntimeErrorKind::NotFound => Self::RUNTIME_NOT_FOUND,
461            RuntimeErrorKind::Unsupported => Self::RUNTIME_UNSUPPORTED,
462            RuntimeErrorKind::Internal => Self::RUNTIME_INTERNAL,
463        }
464    }
465
466    const fn from_runtime_boundary(boundary: RuntimeBoundaryCode) -> Self {
467        Self(Self::RUNTIME_BOUNDARY_SQL_SURFACE_CONTROLLER_REQUIRED.raw() + boundary as u16)
468    }
469
470    const fn from_sql_feature(feature: SqlFeatureCode) -> Self {
471        Self(Self::SQL_FEATURE_AGGREGATE_FILTER_CLAUSE.raw() + feature as u16)
472    }
473
474    const fn from_sql_surface_mismatch(mismatch: SqlSurfaceMismatchCode) -> Self {
475        Self(Self::SQL_SURFACE_QUERY_REJECTS_INSERT.raw() + mismatch as u16)
476    }
477
478    const fn from_schema_ddl(reason: SchemaDdlAdmissionCode) -> Self {
479        Self(Self::SCHEMA_DDL_MISSING_EXPECTED_SCHEMA_VERSION.raw() + reason as u16)
480    }
481
482    const fn query_kind_detail(raw: u16) -> Option<DiagnosticDetail> {
483        match raw {
484            1 => Some(DiagnosticDetail::QueryKind {
485                kind: QueryErrorKind::Validate,
486            }),
487            2 => Some(DiagnosticDetail::QueryKind {
488                kind: QueryErrorKind::Intent,
489            }),
490            3 => Some(DiagnosticDetail::QueryKind {
491                kind: QueryErrorKind::Plan,
492            }),
493            4 => Some(DiagnosticDetail::QueryKind {
494                kind: QueryErrorKind::AccessRequirement,
495            }),
496            5 => Some(DiagnosticDetail::QueryKind {
497                kind: QueryErrorKind::UnorderedPagination,
498            }),
499            6 => Some(DiagnosticDetail::QueryKind {
500                kind: QueryErrorKind::InvalidContinuationCursor,
501            }),
502            7 => Some(DiagnosticDetail::QueryKind {
503                kind: QueryErrorKind::NotFound,
504            }),
505            8 => Some(DiagnosticDetail::QueryKind {
506                kind: QueryErrorKind::NotUnique,
507            }),
508            _ => None,
509        }
510    }
511
512    const fn runtime_kind_detail(raw: u16) -> Option<DiagnosticDetail> {
513        match raw {
514            17 => Some(DiagnosticDetail::RuntimeKind {
515                kind: RuntimeErrorKind::Corruption,
516            }),
517            18 => Some(DiagnosticDetail::RuntimeKind {
518                kind: RuntimeErrorKind::IncompatiblePersistedFormat,
519            }),
520            19 => Some(DiagnosticDetail::RuntimeKind {
521                kind: RuntimeErrorKind::InvariantViolation,
522            }),
523            20 => Some(DiagnosticDetail::RuntimeKind {
524                kind: RuntimeErrorKind::Conflict,
525            }),
526            21 => Some(DiagnosticDetail::RuntimeKind {
527                kind: RuntimeErrorKind::NotFound,
528            }),
529            22 => Some(DiagnosticDetail::RuntimeKind {
530                kind: RuntimeErrorKind::Unsupported,
531            }),
532            23 => Some(DiagnosticDetail::RuntimeKind {
533                kind: RuntimeErrorKind::Internal,
534            }),
535            _ => None,
536        }
537    }
538
539    const fn runtime_boundary_detail(raw: u16) -> Option<DiagnosticDetail> {
540        match raw {
541            24 => Some(DiagnosticDetail::RuntimeBoundary {
542                boundary: RuntimeBoundaryCode::SqlSurfaceControllerRequired,
543            }),
544            25 => Some(DiagnosticDetail::RuntimeBoundary {
545                boundary: RuntimeBoundaryCode::SchemaSurfaceControllerRequired,
546            }),
547            26 => Some(DiagnosticDetail::RuntimeBoundary {
548                boundary: RuntimeBoundaryCode::SqlQueryNoConfiguredEntities,
549            }),
550            27 => Some(DiagnosticDetail::RuntimeBoundary {
551                boundary: RuntimeBoundaryCode::SqlQueryEntityNotConfigured,
552            }),
553            28 => Some(DiagnosticDetail::RuntimeBoundary {
554                boundary: RuntimeBoundaryCode::SqlDdlTargetRequired,
555            }),
556            29 => Some(DiagnosticDetail::RuntimeBoundary {
557                boundary: RuntimeBoundaryCode::SqlDdlEntityNotConfigured,
558            }),
559            30 => Some(DiagnosticDetail::RuntimeBoundary {
560                boundary: RuntimeBoundaryCode::QueryResponseRowsRequired,
561            }),
562            31 => Some(DiagnosticDetail::RuntimeBoundary {
563                boundary: RuntimeBoundaryCode::QueryResponseGroupedRowsRequired,
564            }),
565            32 => Some(DiagnosticDetail::RuntimeBoundary {
566                boundary: RuntimeBoundaryCode::MutationResultEntityRequired,
567            }),
568            33 => Some(DiagnosticDetail::RuntimeBoundary {
569                boundary: RuntimeBoundaryCode::MutationResultEntitiesRequired,
570            }),
571            34 => Some(DiagnosticDetail::RuntimeBoundary {
572                boundary: RuntimeBoundaryCode::MutationResultIdRequired,
573            }),
574            35 => Some(DiagnosticDetail::RuntimeBoundary {
575                boundary: RuntimeBoundaryCode::MutationResultIdsRequired,
576            }),
577            36 => Some(DiagnosticDetail::RuntimeBoundary {
578                boundary: RuntimeBoundaryCode::RowProjectionFieldNotConfigured,
579            }),
580            _ => None,
581        }
582    }
583
584    const fn sql_feature_detail(raw: u16) -> Option<DiagnosticDetail> {
585        let base = Self::SQL_FEATURE_AGGREGATE_FILTER_CLAUSE.raw();
586        if raw < base {
587            return None;
588        }
589
590        let offset = (raw - base) as usize;
591        if offset < Self::SQL_FEATURE_DETAILS.len() {
592            Some(DiagnosticDetail::UnsupportedSqlFeature {
593                feature: Self::SQL_FEATURE_DETAILS[offset],
594            })
595        } else {
596            None
597        }
598    }
599
600    const fn sql_surface_detail(raw: u16) -> Option<DiagnosticDetail> {
601        match raw {
602            100 => Some(DiagnosticDetail::SqlSurfaceMismatch {
603                mismatch: SqlSurfaceMismatchCode::QueryRejectsInsert,
604            }),
605            101 => Some(DiagnosticDetail::SqlSurfaceMismatch {
606                mismatch: SqlSurfaceMismatchCode::QueryRejectsUpdate,
607            }),
608            102 => Some(DiagnosticDetail::SqlSurfaceMismatch {
609                mismatch: SqlSurfaceMismatchCode::QueryRejectsDelete,
610            }),
611            103 => Some(DiagnosticDetail::SqlSurfaceMismatch {
612                mismatch: SqlSurfaceMismatchCode::UpdateRejectsSelect,
613            }),
614            104 => Some(DiagnosticDetail::SqlSurfaceMismatch {
615                mismatch: SqlSurfaceMismatchCode::UpdateRejectsExplain,
616            }),
617            105 => Some(DiagnosticDetail::SqlSurfaceMismatch {
618                mismatch: SqlSurfaceMismatchCode::UpdateRejectsDescribe,
619            }),
620            106 => Some(DiagnosticDetail::SqlSurfaceMismatch {
621                mismatch: SqlSurfaceMismatchCode::UpdateRejectsShowIndexes,
622            }),
623            107 => Some(DiagnosticDetail::SqlSurfaceMismatch {
624                mismatch: SqlSurfaceMismatchCode::UpdateRejectsShowColumns,
625            }),
626            108 => Some(DiagnosticDetail::SqlSurfaceMismatch {
627                mismatch: SqlSurfaceMismatchCode::UpdateRejectsShowEntities,
628            }),
629            109 => Some(DiagnosticDetail::SqlSurfaceMismatch {
630                mismatch: SqlSurfaceMismatchCode::UpdateRejectsShowStores,
631            }),
632            110 => Some(DiagnosticDetail::SqlSurfaceMismatch {
633                mismatch: SqlSurfaceMismatchCode::UpdateRejectsShowMemory,
634            }),
635            _ => None,
636        }
637    }
638
639    const fn schema_ddl_detail(raw: u16) -> Option<DiagnosticDetail> {
640        match raw {
641            111 => Some(DiagnosticDetail::SchemaDdlAdmission {
642                reason: SchemaDdlAdmissionCode::MissingExpectedSchemaVersion,
643            }),
644            112 => Some(DiagnosticDetail::SchemaDdlAdmission {
645                reason: SchemaDdlAdmissionCode::MissingNextSchemaVersion,
646            }),
647            113 => Some(DiagnosticDetail::SchemaDdlAdmission {
648                reason: SchemaDdlAdmissionCode::StaleExpectedSchemaVersion,
649            }),
650            114 => Some(DiagnosticDetail::SchemaDdlAdmission {
651                reason: SchemaDdlAdmissionCode::InvalidExpectedSchemaVersion,
652            }),
653            115 => Some(DiagnosticDetail::SchemaDdlAdmission {
654                reason: SchemaDdlAdmissionCode::InvalidNextSchemaVersion,
655            }),
656            116 => Some(DiagnosticDetail::SchemaDdlAdmission {
657                reason: SchemaDdlAdmissionCode::AcceptedSchemaChangeWithoutVersionBump,
658            }),
659            117 => Some(DiagnosticDetail::SchemaDdlAdmission {
660                reason: SchemaDdlAdmissionCode::EmptyVersionBump,
661            }),
662            118 => Some(DiagnosticDetail::SchemaDdlAdmission {
663                reason: SchemaDdlAdmissionCode::VersionGap,
664            }),
665            119 => Some(DiagnosticDetail::SchemaDdlAdmission {
666                reason: SchemaDdlAdmissionCode::VersionRollback,
667            }),
668            120 => Some(DiagnosticDetail::SchemaDdlAdmission {
669                reason: SchemaDdlAdmissionCode::FingerprintMethodMismatch,
670            }),
671            121 => Some(DiagnosticDetail::SchemaDdlAdmission {
672                reason: SchemaDdlAdmissionCode::UnsupportedTransitionClass,
673            }),
674            122 => Some(DiagnosticDetail::SchemaDdlAdmission {
675                reason: SchemaDdlAdmissionCode::PhysicalRunnerMissing,
676            }),
677            123 => Some(DiagnosticDetail::SchemaDdlAdmission {
678                reason: SchemaDdlAdmissionCode::ValidationFailed,
679            }),
680            124 => Some(DiagnosticDetail::SchemaDdlAdmission {
681                reason: SchemaDdlAdmissionCode::PublicationRaceLost,
682            }),
683            125 => Some(DiagnosticDetail::SchemaDdlAdmission {
684                reason: SchemaDdlAdmissionCode::InvalidAddColumnDefault,
685            }),
686            126 => Some(DiagnosticDetail::SchemaDdlAdmission {
687                reason: SchemaDdlAdmissionCode::InvalidAlterColumnDefault,
688            }),
689            127 => Some(DiagnosticDetail::SchemaDdlAdmission {
690                reason: SchemaDdlAdmissionCode::GeneratedIndexDropRejected,
691            }),
692            128 => Some(DiagnosticDetail::SchemaDdlAdmission {
693                reason: SchemaDdlAdmissionCode::RequiredDropDefaultUnsupported,
694            }),
695            129 => Some(DiagnosticDetail::SchemaDdlAdmission {
696                reason: SchemaDdlAdmissionCode::GeneratedFieldDefaultChangeRejected,
697            }),
698            130 => Some(DiagnosticDetail::SchemaDdlAdmission {
699                reason: SchemaDdlAdmissionCode::GeneratedFieldNullabilityChangeRejected,
700            }),
701            131 => Some(DiagnosticDetail::SchemaDdlAdmission {
702                reason: SchemaDdlAdmissionCode::SetNotNullValidationFailed,
703            }),
704            _ => None,
705        }
706    }
707}
708
709impl std::fmt::Debug for ErrorCode {
710    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
711        f.debug_tuple("ErrorCode").field(&self.0).finish()
712    }
713}
714
715///
716/// ErrorClass
717///
718/// Broad diagnostic class used for recovery decisions.
719///
720
721#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
722pub enum ErrorClass {
723    Query,
724    Corruption,
725    IncompatiblePersistedFormat,
726    NotFound,
727    Internal,
728    Conflict,
729    Unsupported,
730    InvariantViolation,
731}
732
733///
734/// ErrorOrigin
735///
736/// Subsystem that owns the diagnostic.
737///
738
739#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
740pub enum ErrorOrigin {
741    Cursor,
742    Executor,
743    Identity,
744    Index,
745    Interface,
746    Planner,
747    Query,
748    Recovery,
749    Response,
750    Runtime,
751    Serialize,
752    Store,
753}
754
755///
756/// QueryErrorKind
757///
758/// Public query error category.
759///
760
761#[repr(u16)]
762#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
763pub enum QueryErrorKind {
764    Validate,
765    Intent,
766    Plan,
767    AccessRequirement,
768    UnorderedPagination,
769    InvalidContinuationCursor,
770    NotFound,
771    NotUnique,
772}
773
774///
775/// RuntimeErrorKind
776///
777/// Public runtime error category.
778///
779
780#[repr(u16)]
781#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
782pub enum RuntimeErrorKind {
783    Corruption,
784    IncompatiblePersistedFormat,
785    InvariantViolation,
786    Conflict,
787    NotFound,
788    Unsupported,
789    Internal,
790}
791
792///
793/// RuntimeBoundaryCode
794///
795/// Compact public-runtime boundary identifier.
796///
797
798#[repr(u16)]
799#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
800pub enum RuntimeBoundaryCode {
801    SqlSurfaceControllerRequired,
802    SchemaSurfaceControllerRequired,
803    SqlQueryNoConfiguredEntities,
804    SqlQueryEntityNotConfigured,
805    SqlDdlTargetRequired,
806    SqlDdlEntityNotConfigured,
807    QueryResponseRowsRequired,
808    QueryResponseGroupedRowsRequired,
809    MutationResultEntityRequired,
810    MutationResultEntitiesRequired,
811    MutationResultIdRequired,
812    MutationResultIdsRequired,
813    RowProjectionFieldNotConfigured,
814}
815
816///
817/// SqlFeatureCode
818///
819/// Compact SQL feature identifier used by unsupported-feature diagnostics.
820///
821
822#[repr(u16)]
823#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
824pub enum SqlFeatureCode {
825    AggregateFilterClause,
826    AlterStatementBeyondAlterTable,
827    AlterTableAddColumnDuplicateDefault,
828    AlterTableAddColumnModifiers,
829    AlterTableAddStatementBeyondAddColumn,
830    AlterTableAlterColumnDropUnsupportedAction,
831    AlterTableAlterColumnModifiers,
832    AlterTableAlterColumnSetUnsupportedAction,
833    AlterTableAlterColumnUnsupportedAction,
834    AlterTableAlterStatementBeyondAlterColumn,
835    AlterTableDropColumnIfExistsSyntax,
836    AlterTableDropColumnModifiers,
837    AlterTableDropStatementBeyondDropColumn,
838    AlterTableRenameColumnMissingTo,
839    AlterTableRenameColumnModifiers,
840    AlterTableRenameStatementBeyondRenameColumn,
841    AlterTableUnsupportedOperation,
842    ColumnAlias,
843    CreateIndexIfNotExistsSyntax,
844    CreateIndexKeyOrderingModifiers,
845    CreateIndexModifiers,
846    CreateStatementBeyondCreateIndex,
847    DescribeModifier,
848    DdlSchemaVersionDuplicateExpectedClause,
849    DdlSchemaVersionDuplicateSetClause,
850    DropIndexModifiers,
851    DropIndexIfExistsSyntax,
852    DropStatementBeyondDropIndex,
853    ExpressionIndexUnsupportedFunction,
854    Having,
855    Insert,
856    Join,
857    LikePatternBeyondTrailingPrefix,
858    LowerFieldPredicateUnsupported,
859    MultiStatementSql,
860    NestedAggregateInput,
861    NestedProjectionFunctionInArithmetic,
862    OrderByUnsupportedForm,
863    Other,
864    ParameterBinding,
865    ParameterizedSchemaVersion,
866    PredicateStartsWithFirstArgument,
867    QuotedIdentifiers,
868    ReturningUnsupportedShape,
869    ScalarFunctionExpressionPosition,
870    ScaleTakingNumericFunctionExpressionPosition,
871    SearchedCaseGroupedOrderBy,
872    ShowColumnsModifiers,
873    ShowEntitiesModifiers,
874    ShowIndexesModifiers,
875    ShowMemoryModifiers,
876    ShowStoresModifiers,
877    ShowUnsupportedCommand,
878    SimpleCaseExpression,
879    StandaloneLiteralProjectionItem,
880    SupportedGroupedOrderByExpressionFamily,
881    SupportedOrderByExpressionFamily,
882    UnionIntersectExcept,
883    UnsupportedFunctionNamespace,
884    Update,
885    UpperFieldPredicateUnsupported,
886    WindowFunction,
887    With,
888}
889
890///
891/// SqlSurfaceMismatchCode
892///
893/// Compact SQL endpoint surface mismatch identifier.
894///
895
896#[repr(u16)]
897#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
898pub enum SqlSurfaceMismatchCode {
899    QueryRejectsInsert,
900    QueryRejectsUpdate,
901    QueryRejectsDelete,
902    UpdateRejectsSelect,
903    UpdateRejectsExplain,
904    UpdateRejectsDescribe,
905    UpdateRejectsShowIndexes,
906    UpdateRejectsShowColumns,
907    UpdateRejectsShowEntities,
908    UpdateRejectsShowStores,
909    UpdateRejectsShowMemory,
910}
911
912///
913/// SchemaDdlAdmissionCode
914///
915/// Compact SQL DDL admission rejection reason.
916///
917
918#[repr(u16)]
919#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
920pub enum SchemaDdlAdmissionCode {
921    MissingExpectedSchemaVersion,
922    MissingNextSchemaVersion,
923    StaleExpectedSchemaVersion,
924    InvalidExpectedSchemaVersion,
925    InvalidNextSchemaVersion,
926    AcceptedSchemaChangeWithoutVersionBump,
927    EmptyVersionBump,
928    VersionGap,
929    VersionRollback,
930    FingerprintMethodMismatch,
931    UnsupportedTransitionClass,
932    PhysicalRunnerMissing,
933    ValidationFailed,
934    PublicationRaceLost,
935    InvalidAddColumnDefault,
936    InvalidAlterColumnDefault,
937    GeneratedIndexDropRejected,
938    RequiredDropDefaultUnsupported,
939    GeneratedFieldDefaultChangeRejected,
940    GeneratedFieldNullabilityChangeRejected,
941    SetNotNullValidationFailed,
942}
943
944///
945/// DiagnosticDetail
946///
947/// Small structured diagnostic payload for callers and CLI rendering.
948///
949
950#[derive(Clone, Copy, Debug, Eq, PartialEq)]
951pub enum DiagnosticDetail {
952    QueryKind { kind: QueryErrorKind },
953    RuntimeKind { kind: RuntimeErrorKind },
954    RuntimeBoundary { boundary: RuntimeBoundaryCode },
955    SchemaDdlAdmission { reason: SchemaDdlAdmissionCode },
956    UnsupportedSqlFeature { feature: SqlFeatureCode },
957    SqlSurfaceMismatch { mismatch: SqlSurfaceMismatchCode },
958}
959
960///
961/// Diagnostic
962///
963/// Compact public diagnostic payload.
964///
965
966#[derive(Clone, Debug, Eq, PartialEq)]
967pub struct Diagnostic {
968    code: DiagnosticCode,
969    origin: ErrorOrigin,
970    detail: Option<DiagnosticDetail>,
971}
972
973impl Diagnostic {
974    /// Build a compact diagnostic from a code and optional structured detail.
975    #[must_use]
976    pub const fn new(
977        code: DiagnosticCode,
978        origin: ErrorOrigin,
979        detail: Option<DiagnosticDetail>,
980    ) -> Self {
981        Self {
982            code,
983            origin,
984            detail,
985        }
986    }
987
988    /// Build a compact diagnostic using the code's default origin.
989    #[must_use]
990    pub const fn from_code(code: DiagnosticCode) -> Self {
991        Self::new(code, code.origin(), None)
992    }
993
994    /// Return the stable diagnostic code.
995    #[must_use]
996    pub const fn code(&self) -> DiagnosticCode {
997        self.code
998    }
999
1000    /// Return the diagnostic class.
1001    #[must_use]
1002    pub const fn class(&self) -> ErrorClass {
1003        self.code.class()
1004    }
1005
1006    /// Return the subsystem origin.
1007    #[must_use]
1008    pub const fn origin(&self) -> ErrorOrigin {
1009        self.origin
1010    }
1011
1012    /// Return structured diagnostic detail, when available.
1013    #[must_use]
1014    pub const fn detail(&self) -> Option<&DiagnosticDetail> {
1015        self.detail.as_ref()
1016    }
1017
1018    /// Return the numeric public wire code for this diagnostic.
1019    #[must_use]
1020    pub const fn error_code(&self) -> ErrorCode {
1021        ErrorCode::from_parts(self.code, self.detail)
1022    }
1023}
1024
1025#[cfg(test)]
1026mod tests {
1027    use super::{Diagnostic, DiagnosticCode, ErrorClass, ErrorCode, ErrorOrigin};
1028
1029    const ORDERED_ERROR_CODES: [ErrorCode; 131] = [
1030        ErrorCode::QUERY_VALIDATE,
1031        ErrorCode::QUERY_INTENT,
1032        ErrorCode::QUERY_PLAN,
1033        ErrorCode::QUERY_ACCESS_REQUIREMENT,
1034        ErrorCode::QUERY_UNORDERED_PAGINATION,
1035        ErrorCode::QUERY_INVALID_CONTINUATION_CURSOR,
1036        ErrorCode::QUERY_NOT_FOUND,
1037        ErrorCode::QUERY_NOT_UNIQUE,
1038        ErrorCode::QUERY_NUMERIC_OVERFLOW,
1039        ErrorCode::QUERY_NUMERIC_NOT_REPRESENTABLE,
1040        ErrorCode::QUERY_UNSUPPORTED_SQL_FEATURE,
1041        ErrorCode::QUERY_SQL_SURFACE_MISMATCH,
1042        ErrorCode::SCHEMA_DDL_ADMISSION,
1043        ErrorCode::STORE_NOT_FOUND,
1044        ErrorCode::STORE_CORRUPTION,
1045        ErrorCode::STORE_INVARIANT_VIOLATION,
1046        ErrorCode::RUNTIME_CORRUPTION,
1047        ErrorCode::RUNTIME_INCOMPATIBLE_PERSISTED_FORMAT,
1048        ErrorCode::RUNTIME_INVARIANT_VIOLATION,
1049        ErrorCode::RUNTIME_CONFLICT,
1050        ErrorCode::RUNTIME_NOT_FOUND,
1051        ErrorCode::RUNTIME_UNSUPPORTED,
1052        ErrorCode::RUNTIME_INTERNAL,
1053        ErrorCode::RUNTIME_BOUNDARY_SQL_SURFACE_CONTROLLER_REQUIRED,
1054        ErrorCode::RUNTIME_BOUNDARY_SCHEMA_SURFACE_CONTROLLER_REQUIRED,
1055        ErrorCode::RUNTIME_BOUNDARY_SQL_QUERY_NO_CONFIGURED_ENTITIES,
1056        ErrorCode::RUNTIME_BOUNDARY_SQL_QUERY_ENTITY_NOT_CONFIGURED,
1057        ErrorCode::RUNTIME_BOUNDARY_SQL_DDL_TARGET_REQUIRED,
1058        ErrorCode::RUNTIME_BOUNDARY_SQL_DDL_ENTITY_NOT_CONFIGURED,
1059        ErrorCode::RUNTIME_BOUNDARY_QUERY_RESPONSE_ROWS_REQUIRED,
1060        ErrorCode::RUNTIME_BOUNDARY_QUERY_RESPONSE_GROUPED_ROWS_REQUIRED,
1061        ErrorCode::RUNTIME_BOUNDARY_MUTATION_RESULT_ENTITY_REQUIRED,
1062        ErrorCode::RUNTIME_BOUNDARY_MUTATION_RESULT_ENTITIES_REQUIRED,
1063        ErrorCode::RUNTIME_BOUNDARY_MUTATION_RESULT_ID_REQUIRED,
1064        ErrorCode::RUNTIME_BOUNDARY_MUTATION_RESULT_IDS_REQUIRED,
1065        ErrorCode::RUNTIME_BOUNDARY_ROW_PROJECTION_FIELD_NOT_CONFIGURED,
1066        ErrorCode::SQL_FEATURE_AGGREGATE_FILTER_CLAUSE,
1067        ErrorCode::SQL_FEATURE_ALTER_STATEMENT_BEYOND_ALTER_TABLE,
1068        ErrorCode::SQL_FEATURE_ALTER_TABLE_ADD_COLUMN_DUPLICATE_DEFAULT,
1069        ErrorCode::SQL_FEATURE_ALTER_TABLE_ADD_COLUMN_MODIFIERS,
1070        ErrorCode::SQL_FEATURE_ALTER_TABLE_ADD_STATEMENT_BEYOND_ADD_COLUMN,
1071        ErrorCode::SQL_FEATURE_ALTER_TABLE_ALTER_COLUMN_DROP_UNSUPPORTED_ACTION,
1072        ErrorCode::SQL_FEATURE_ALTER_TABLE_ALTER_COLUMN_MODIFIERS,
1073        ErrorCode::SQL_FEATURE_ALTER_TABLE_ALTER_COLUMN_SET_UNSUPPORTED_ACTION,
1074        ErrorCode::SQL_FEATURE_ALTER_TABLE_ALTER_COLUMN_UNSUPPORTED_ACTION,
1075        ErrorCode::SQL_FEATURE_ALTER_TABLE_ALTER_STATEMENT_BEYOND_ALTER_COLUMN,
1076        ErrorCode::SQL_FEATURE_ALTER_TABLE_DROP_COLUMN_IF_EXISTS_SYNTAX,
1077        ErrorCode::SQL_FEATURE_ALTER_TABLE_DROP_COLUMN_MODIFIERS,
1078        ErrorCode::SQL_FEATURE_ALTER_TABLE_DROP_STATEMENT_BEYOND_DROP_COLUMN,
1079        ErrorCode::SQL_FEATURE_ALTER_TABLE_RENAME_COLUMN_MISSING_TO,
1080        ErrorCode::SQL_FEATURE_ALTER_TABLE_RENAME_COLUMN_MODIFIERS,
1081        ErrorCode::SQL_FEATURE_ALTER_TABLE_RENAME_STATEMENT_BEYOND_RENAME_COLUMN,
1082        ErrorCode::SQL_FEATURE_ALTER_TABLE_UNSUPPORTED_OPERATION,
1083        ErrorCode::SQL_FEATURE_COLUMN_ALIAS,
1084        ErrorCode::SQL_FEATURE_CREATE_INDEX_IF_NOT_EXISTS_SYNTAX,
1085        ErrorCode::SQL_FEATURE_CREATE_INDEX_KEY_ORDERING_MODIFIERS,
1086        ErrorCode::SQL_FEATURE_CREATE_INDEX_MODIFIERS,
1087        ErrorCode::SQL_FEATURE_CREATE_STATEMENT_BEYOND_CREATE_INDEX,
1088        ErrorCode::SQL_FEATURE_DESCRIBE_MODIFIER,
1089        ErrorCode::SQL_FEATURE_DDL_SCHEMA_VERSION_DUPLICATE_EXPECTED_CLAUSE,
1090        ErrorCode::SQL_FEATURE_DDL_SCHEMA_VERSION_DUPLICATE_SET_CLAUSE,
1091        ErrorCode::SQL_FEATURE_DROP_INDEX_MODIFIERS,
1092        ErrorCode::SQL_FEATURE_DROP_INDEX_IF_EXISTS_SYNTAX,
1093        ErrorCode::SQL_FEATURE_DROP_STATEMENT_BEYOND_DROP_INDEX,
1094        ErrorCode::SQL_FEATURE_EXPRESSION_INDEX_UNSUPPORTED_FUNCTION,
1095        ErrorCode::SQL_FEATURE_HAVING,
1096        ErrorCode::SQL_FEATURE_INSERT,
1097        ErrorCode::SQL_FEATURE_JOIN,
1098        ErrorCode::SQL_FEATURE_LIKE_PATTERN_BEYOND_TRAILING_PREFIX,
1099        ErrorCode::SQL_FEATURE_LOWER_FIELD_PREDICATE_UNSUPPORTED,
1100        ErrorCode::SQL_FEATURE_MULTI_STATEMENT_SQL,
1101        ErrorCode::SQL_FEATURE_NESTED_AGGREGATE_INPUT,
1102        ErrorCode::SQL_FEATURE_NESTED_PROJECTION_FUNCTION_IN_ARITHMETIC,
1103        ErrorCode::SQL_FEATURE_ORDER_BY_UNSUPPORTED_FORM,
1104        ErrorCode::SQL_FEATURE_OTHER,
1105        ErrorCode::SQL_FEATURE_PARAMETER_BINDING,
1106        ErrorCode::SQL_FEATURE_PARAMETERIZED_SCHEMA_VERSION,
1107        ErrorCode::SQL_FEATURE_PREDICATE_STARTS_WITH_FIRST_ARGUMENT,
1108        ErrorCode::SQL_FEATURE_QUOTED_IDENTIFIERS,
1109        ErrorCode::SQL_FEATURE_RETURNING_UNSUPPORTED_SHAPE,
1110        ErrorCode::SQL_FEATURE_SCALAR_FUNCTION_EXPRESSION_POSITION,
1111        ErrorCode::SQL_FEATURE_SCALE_TAKING_NUMERIC_FUNCTION_EXPRESSION_POSITION,
1112        ErrorCode::SQL_FEATURE_SEARCHED_CASE_GROUPED_ORDER_BY,
1113        ErrorCode::SQL_FEATURE_SHOW_COLUMNS_MODIFIERS,
1114        ErrorCode::SQL_FEATURE_SHOW_ENTITIES_MODIFIERS,
1115        ErrorCode::SQL_FEATURE_SHOW_INDEXES_MODIFIERS,
1116        ErrorCode::SQL_FEATURE_SHOW_MEMORY_MODIFIERS,
1117        ErrorCode::SQL_FEATURE_SHOW_STORES_MODIFIERS,
1118        ErrorCode::SQL_FEATURE_SHOW_UNSUPPORTED_COMMAND,
1119        ErrorCode::SQL_FEATURE_SIMPLE_CASE_EXPRESSION,
1120        ErrorCode::SQL_FEATURE_STANDALONE_LITERAL_PROJECTION_ITEM,
1121        ErrorCode::SQL_FEATURE_SUPPORTED_GROUPED_ORDER_BY_EXPRESSION_FAMILY,
1122        ErrorCode::SQL_FEATURE_SUPPORTED_ORDER_BY_EXPRESSION_FAMILY,
1123        ErrorCode::SQL_FEATURE_UNION_INTERSECT_EXCEPT,
1124        ErrorCode::SQL_FEATURE_UNSUPPORTED_FUNCTION_NAMESPACE,
1125        ErrorCode::SQL_FEATURE_UPDATE,
1126        ErrorCode::SQL_FEATURE_UPPER_FIELD_PREDICATE_UNSUPPORTED,
1127        ErrorCode::SQL_FEATURE_WINDOW_FUNCTION,
1128        ErrorCode::SQL_FEATURE_WITH,
1129        ErrorCode::SQL_SURFACE_QUERY_REJECTS_INSERT,
1130        ErrorCode::SQL_SURFACE_QUERY_REJECTS_UPDATE,
1131        ErrorCode::SQL_SURFACE_QUERY_REJECTS_DELETE,
1132        ErrorCode::SQL_SURFACE_UPDATE_REJECTS_SELECT,
1133        ErrorCode::SQL_SURFACE_UPDATE_REJECTS_EXPLAIN,
1134        ErrorCode::SQL_SURFACE_UPDATE_REJECTS_DESCRIBE,
1135        ErrorCode::SQL_SURFACE_UPDATE_REJECTS_SHOW_INDEXES,
1136        ErrorCode::SQL_SURFACE_UPDATE_REJECTS_SHOW_COLUMNS,
1137        ErrorCode::SQL_SURFACE_UPDATE_REJECTS_SHOW_ENTITIES,
1138        ErrorCode::SQL_SURFACE_UPDATE_REJECTS_SHOW_STORES,
1139        ErrorCode::SQL_SURFACE_UPDATE_REJECTS_SHOW_MEMORY,
1140        ErrorCode::SCHEMA_DDL_MISSING_EXPECTED_SCHEMA_VERSION,
1141        ErrorCode::SCHEMA_DDL_MISSING_NEXT_SCHEMA_VERSION,
1142        ErrorCode::SCHEMA_DDL_STALE_EXPECTED_SCHEMA_VERSION,
1143        ErrorCode::SCHEMA_DDL_INVALID_EXPECTED_SCHEMA_VERSION,
1144        ErrorCode::SCHEMA_DDL_INVALID_NEXT_SCHEMA_VERSION,
1145        ErrorCode::SCHEMA_DDL_ACCEPTED_SCHEMA_CHANGE_WITHOUT_VERSION_BUMP,
1146        ErrorCode::SCHEMA_DDL_EMPTY_VERSION_BUMP,
1147        ErrorCode::SCHEMA_DDL_VERSION_GAP,
1148        ErrorCode::SCHEMA_DDL_VERSION_ROLLBACK,
1149        ErrorCode::SCHEMA_DDL_FINGERPRINT_METHOD_MISMATCH,
1150        ErrorCode::SCHEMA_DDL_UNSUPPORTED_TRANSITION_CLASS,
1151        ErrorCode::SCHEMA_DDL_PHYSICAL_RUNNER_MISSING,
1152        ErrorCode::SCHEMA_DDL_VALIDATION_FAILED,
1153        ErrorCode::SCHEMA_DDL_PUBLICATION_RACE_LOST,
1154        ErrorCode::SCHEMA_DDL_INVALID_ADD_COLUMN_DEFAULT,
1155        ErrorCode::SCHEMA_DDL_INVALID_ALTER_COLUMN_DEFAULT,
1156        ErrorCode::SCHEMA_DDL_GENERATED_INDEX_DROP_REJECTED,
1157        ErrorCode::SCHEMA_DDL_REQUIRED_DROP_DEFAULT_UNSUPPORTED,
1158        ErrorCode::SCHEMA_DDL_GENERATED_FIELD_DEFAULT_CHANGE_REJECTED,
1159        ErrorCode::SCHEMA_DDL_GENERATED_FIELD_NULLABILITY_CHANGE_REJECTED,
1160        ErrorCode::SCHEMA_DDL_SET_NOT_NULL_VALIDATION_FAILED,
1161    ];
1162
1163    #[test]
1164    fn diagnostic_from_code_uses_default_origin() {
1165        let diagnostic = Diagnostic::from_code(DiagnosticCode::QueryPlan);
1166
1167        assert_eq!(diagnostic.code(), DiagnosticCode::QueryPlan);
1168        assert_eq!(diagnostic.origin(), ErrorOrigin::Query);
1169    }
1170
1171    #[test]
1172    fn diagnostic_code_reports_broad_class() {
1173        assert_eq!(
1174            DiagnosticCode::QueryUnsupportedSqlFeature.class(),
1175            ErrorClass::Unsupported
1176        );
1177        assert_eq!(
1178            DiagnosticCode::QuerySqlSurfaceMismatch.class(),
1179            ErrorClass::Unsupported
1180        );
1181        assert_eq!(DiagnosticCode::QueryPlan.class(), ErrorClass::Query);
1182        assert_eq!(
1183            DiagnosticCode::StoreCorruption.class(),
1184            ErrorClass::Corruption
1185        );
1186    }
1187
1188    #[test]
1189    fn public_error_codes_are_sequential() {
1190        for (index, code) in ORDERED_ERROR_CODES.iter().enumerate() {
1191            let expected = u16::try_from(index + 1).expect("test error-code index fits u16");
1192            assert_eq!(code.raw(), expected);
1193        }
1194    }
1195}