Skip to main content

icydb_diagnostic_code/
lib.rs

1//! Module: lib
2//! Responsibility: compact diagnostic identity and public numeric error-code mapping.
3//! Does not own: rich diagnostic prose, Wire wire types, or runtime error construction.
4//! Boundary: maps rich internal diagnostic categories to stable compact public codes.
5//!
6//! This crate intentionally contains no rich diagnostic prose or Wire wire
7//! types. Production canister builds collapse diagnostics to numeric wire
8//! codes before they cross the public canister boundary. `Debug` output is
9//! numeric for the same reason: host tooling can recover labels from the code
10//! table without making every wasm canister retain those labels.
11
12use std::fmt;
13
14mod fact;
15mod query_field;
16
17pub use fact::{
18    DiagnosticAggregateKind, DiagnosticBacklogResource, DiagnosticComponentKind,
19    DiagnosticConstraintContext, DiagnosticConstraintKind, DiagnosticDecodeReason,
20    DiagnosticExecutionBudgetResource, DiagnosticExecutionBudgetScope, DiagnosticExecutionLane,
21    DiagnosticFactSchemaMismatch, DiagnosticFactTag, DiagnosticFunctionKind,
22    DiagnosticGroupBudgetResource, DiagnosticMutationOperation, DiagnosticOperatorKind,
23    DiagnosticTypeFamily, MAX_PUBLIC_DIAGNOSTIC_FACTS, pack_u32_pair, unpack_u32_pair,
24    validate_known_diagnostic_fact_schema, validate_raw_diagnostic_fact_schema,
25};
26pub use query_field::{
27    MAX_PUBLIC_QUERY_FIELD_BYTES, QueryFieldRole, QueryFieldSchemaMismatch,
28    validate_query_field_schema,
29};
30
31///
32/// DiagnosticCode
33///
34/// Stable machine-readable diagnostic reason.
35///
36
37#[remain::sorted]
38#[derive(Clone, Copy, Eq, Hash, PartialEq)]
39pub enum DiagnosticCode {
40    /// An admitted exact count has no available exact-cardinality metadata.
41    QueryExactCountMetadataUnavailable,
42    QueryIntent,
43    QueryInvalidContinuationCursor,
44    QueryNotFound,
45    QueryNotUnique,
46    QueryNumericNotRepresentable,
47    QueryNumericOverflow,
48    QueryPlan,
49    QueryReadAdmission,
50    QuerySqlSurfaceMismatch,
51    QuerySqlWriteBoundary,
52    QueryUnknownAggregateTargetField,
53    QueryUnorderedPagination,
54    QueryUnsupportedProjection,
55    QueryUnsupportedSqlFeature,
56    QueryValidate,
57    RuntimeConflict,
58    RuntimeCorruption,
59    RuntimeIncompatiblePersistedFormat,
60    RuntimeInternal,
61    RuntimeInvariantViolation,
62    RuntimeNotFound,
63    RuntimeUnsupported,
64    SchemaDdlAdmission,
65    StoreCorruption,
66    StoreInvariantViolation,
67    StoreNotFound,
68}
69
70impl DiagnosticCode {
71    /// Return the broad diagnostic class for this code.
72    #[must_use]
73    pub const fn class(self) -> ErrorClass {
74        match self {
75            Self::StoreCorruption | Self::RuntimeCorruption => ErrorClass::Corruption,
76            Self::RuntimeIncompatiblePersistedFormat => ErrorClass::IncompatiblePersistedFormat,
77            Self::QueryNotFound | Self::StoreNotFound | Self::RuntimeNotFound => {
78                ErrorClass::NotFound
79            }
80            Self::RuntimeConflict => ErrorClass::Conflict,
81            Self::QueryExactCountMetadataUnavailable
82            | Self::QueryUnsupportedSqlFeature
83            | Self::QueryUnknownAggregateTargetField
84            | Self::QueryUnsupportedProjection
85            | Self::QuerySqlSurfaceMismatch
86            | Self::QuerySqlWriteBoundary
87            | Self::RuntimeUnsupported => ErrorClass::Unsupported,
88            Self::StoreInvariantViolation | Self::RuntimeInvariantViolation => {
89                ErrorClass::InvariantViolation
90            }
91            Self::RuntimeInternal => ErrorClass::Internal,
92            Self::QueryValidate
93            | Self::QueryIntent
94            | Self::QueryPlan
95            | Self::QueryReadAdmission
96            | Self::QueryUnorderedPagination
97            | Self::QueryInvalidContinuationCursor
98            | Self::QueryNotUnique
99            | Self::QueryNumericOverflow
100            | Self::QueryNumericNotRepresentable
101            | Self::SchemaDdlAdmission => ErrorClass::Query,
102        }
103    }
104
105    /// Return the default diagnostic origin for this code.
106    #[must_use]
107    pub const fn origin(self) -> ErrorOrigin {
108        match self {
109            Self::StoreNotFound | Self::StoreCorruption | Self::StoreInvariantViolation => {
110                ErrorOrigin::Store
111            }
112            Self::RuntimeCorruption
113            | Self::RuntimeIncompatiblePersistedFormat
114            | Self::RuntimeInvariantViolation
115            | Self::RuntimeConflict
116            | Self::RuntimeNotFound
117            | Self::RuntimeUnsupported
118            | Self::RuntimeInternal => ErrorOrigin::Runtime,
119            Self::QueryExactCountMetadataUnavailable
120            | Self::QueryValidate
121            | Self::QueryIntent
122            | Self::QueryPlan
123            | Self::QueryReadAdmission
124            | Self::QueryUnorderedPagination
125            | Self::QueryInvalidContinuationCursor
126            | Self::QueryNotFound
127            | Self::QueryNotUnique
128            | Self::QueryNumericOverflow
129            | Self::QueryNumericNotRepresentable
130            | Self::QueryUnknownAggregateTargetField
131            | Self::QueryUnsupportedProjection
132            | Self::QueryUnsupportedSqlFeature
133            | Self::QuerySqlSurfaceMismatch
134            | Self::QuerySqlWriteBoundary
135            | Self::SchemaDdlAdmission => ErrorOrigin::Query,
136        }
137    }
138
139    /// Return the compact public wire code for this broad diagnostic reason.
140    #[must_use]
141    pub const fn error_code(self) -> ErrorCode {
142        match self {
143            Self::QueryExactCountMetadataUnavailable => {
144                ErrorCode::QUERY_EXACT_COUNT_METADATA_UNAVAILABLE
145            }
146            Self::QueryValidate => ErrorCode::QUERY_VALIDATE,
147            Self::QueryIntent => ErrorCode::QUERY_INTENT,
148            Self::QueryPlan => ErrorCode::QUERY_PLAN,
149            Self::QueryReadAdmission => ErrorCode::QUERY_READ_ADMISSION,
150            Self::QueryUnorderedPagination => ErrorCode::QUERY_UNORDERED_PAGINATION,
151            Self::QueryInvalidContinuationCursor => ErrorCode::QUERY_INVALID_CONTINUATION_CURSOR,
152            Self::QueryNotFound => ErrorCode::QUERY_NOT_FOUND,
153            Self::QueryNotUnique => ErrorCode::QUERY_NOT_UNIQUE,
154            Self::QueryNumericOverflow => ErrorCode::QUERY_NUMERIC_OVERFLOW,
155            Self::QueryNumericNotRepresentable => ErrorCode::QUERY_NUMERIC_NOT_REPRESENTABLE,
156            Self::QueryUnknownAggregateTargetField => {
157                ErrorCode::QUERY_UNKNOWN_AGGREGATE_TARGET_FIELD
158            }
159            Self::QueryUnsupportedProjection => ErrorCode::QUERY_UNSUPPORTED_PROJECTION,
160            Self::QueryUnsupportedSqlFeature => ErrorCode::QUERY_UNSUPPORTED_SQL_FEATURE,
161            Self::QuerySqlSurfaceMismatch => ErrorCode::QUERY_SQL_SURFACE_MISMATCH,
162            Self::QuerySqlWriteBoundary => ErrorCode::QUERY_SQL_WRITE_BOUNDARY,
163            Self::SchemaDdlAdmission => ErrorCode::SCHEMA_DDL_ADMISSION,
164            Self::StoreNotFound => ErrorCode::STORE_NOT_FOUND,
165            Self::StoreCorruption => ErrorCode::STORE_CORRUPTION,
166            Self::StoreInvariantViolation => ErrorCode::STORE_INVARIANT_VIOLATION,
167            Self::RuntimeCorruption => ErrorCode::RUNTIME_CORRUPTION,
168            Self::RuntimeIncompatiblePersistedFormat => {
169                ErrorCode::RUNTIME_INCOMPATIBLE_PERSISTED_FORMAT
170            }
171            Self::RuntimeInvariantViolation => ErrorCode::RUNTIME_INVARIANT_VIOLATION,
172            Self::RuntimeConflict => ErrorCode::RUNTIME_CONFLICT,
173            Self::RuntimeNotFound => ErrorCode::RUNTIME_NOT_FOUND,
174            Self::RuntimeUnsupported => ErrorCode::RUNTIME_UNSUPPORTED,
175            Self::RuntimeInternal => ErrorCode::RUNTIME_INTERNAL,
176        }
177    }
178}
179
180impl fmt::Debug for DiagnosticCode {
181    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182        fmt_compact_code(f, self.error_code().raw())
183    }
184}
185
186///
187/// ErrorCode
188///
189/// Stable numeric public error identity.
190///
191/// The public Wire `icydb::Error` stores this value as native `u16` so canister
192/// interfaces do not retain rich diagnostic enum labels. Rich diagnostics can
193/// still be reconstructed by host-side tooling from this leaf code. Before
194/// 1.0.0, the code space is hard-cut to a single compact sequential range.
195///
196
197#[derive(Clone, Copy, Eq, Hash, PartialEq)]
198pub struct ErrorCode(u16);
199
200mod registry;
201
202impl ErrorCode {
203    /// Build an error code from its raw public wire value.
204    #[must_use]
205    pub const fn from_raw(raw: u16) -> Self {
206        Self(raw)
207    }
208
209    /// Return the raw public wire value.
210    #[must_use]
211    pub const fn raw(self) -> u16 {
212        self.0
213    }
214}
215
216impl fmt::Debug for ErrorCode {
217    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218        fmt_compact_code(f, self.raw())
219    }
220}
221
222///
223/// ErrorClass
224///
225/// Broad diagnostic class used for recovery decisions.
226///
227
228#[remain::sorted]
229#[derive(Clone, Copy, Eq, Hash, PartialEq)]
230pub enum ErrorClass {
231    Conflict,
232    Corruption,
233    IncompatiblePersistedFormat,
234    Internal,
235    InvariantViolation,
236    NotFound,
237    Query,
238    Unsupported,
239}
240
241impl ErrorClass {
242    /// Return the compact public wire code for this diagnostic class.
243    #[must_use]
244    pub const fn wire_code(self) -> u8 {
245        match self {
246            Self::Query => 1,
247            Self::Corruption => 2,
248            Self::IncompatiblePersistedFormat => 3,
249            Self::NotFound => 4,
250            Self::Internal => 5,
251            Self::Conflict => 6,
252            Self::Unsupported => 7,
253            Self::InvariantViolation => 8,
254        }
255    }
256
257    /// Recover a diagnostic class from its compact public wire code.
258    #[must_use]
259    pub const fn from_wire_code(code: u8) -> Option<Self> {
260        match code {
261            1 => Some(Self::Query),
262            2 => Some(Self::Corruption),
263            3 => Some(Self::IncompatiblePersistedFormat),
264            4 => Some(Self::NotFound),
265            5 => Some(Self::Internal),
266            6 => Some(Self::Conflict),
267            7 => Some(Self::Unsupported),
268            8 => Some(Self::InvariantViolation),
269            _ => None,
270        }
271    }
272}
273
274impl fmt::Debug for ErrorClass {
275    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
276        fmt_compact_code(f, u16::from(self.wire_code()))
277    }
278}
279
280///
281/// ErrorOrigin
282///
283/// Subsystem that owns the diagnostic.
284///
285
286#[remain::sorted]
287#[derive(Clone, Copy, Eq, Hash, PartialEq)]
288pub enum ErrorOrigin {
289    Cursor,
290    Executor,
291    Identity,
292    Index,
293    Interface,
294    Planner,
295    Query,
296    Recovery,
297    Response,
298    Runtime,
299    Serialize,
300    Store,
301}
302
303impl ErrorOrigin {
304    /// Return the compact public wire code for this diagnostic origin.
305    #[must_use]
306    pub const fn wire_code(self) -> u8 {
307        match self {
308            Self::Cursor => 1,
309            Self::Executor => 2,
310            Self::Identity => 3,
311            Self::Index => 4,
312            Self::Interface => 5,
313            Self::Planner => 6,
314            Self::Query => 7,
315            Self::Recovery => 8,
316            Self::Response => 9,
317            Self::Runtime => 10,
318            Self::Serialize => 11,
319            Self::Store => 12,
320        }
321    }
322
323    /// Recover a known diagnostic origin from its compact public wire code.
324    #[must_use]
325    pub const fn from_known_wire_code(code: u8) -> Option<Self> {
326        match code {
327            1 => Some(Self::Cursor),
328            2 => Some(Self::Executor),
329            3 => Some(Self::Identity),
330            4 => Some(Self::Index),
331            5 => Some(Self::Interface),
332            6 => Some(Self::Planner),
333            7 => Some(Self::Query),
334            8 => Some(Self::Recovery),
335            9 => Some(Self::Response),
336            10 => Some(Self::Runtime),
337            11 => Some(Self::Serialize),
338            12 => Some(Self::Store),
339            _ => None,
340        }
341    }
342
343    /// Recover a diagnostic origin from its compact public wire code.
344    ///
345    /// Unknown origin codes fail closed to `Runtime`, matching the public
346    /// boundary behavior used by the Wire facade.
347    #[must_use]
348    pub const fn from_wire_code(code: u8) -> Self {
349        match Self::from_known_wire_code(code) {
350            Some(origin) => origin,
351            None => Self::Runtime,
352        }
353    }
354}
355
356impl fmt::Debug for ErrorOrigin {
357    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
358        fmt_compact_code(f, u16::from(self.wire_code()))
359    }
360}
361
362///
363/// QueryErrorKind
364///
365/// Public query error category.
366///
367
368#[repr(u16)]
369#[derive(Clone, Copy, Eq, Hash, PartialEq)]
370pub enum QueryErrorKind {
371    Validate,
372    Intent,
373    Plan,
374    UnorderedPagination,
375    InvalidContinuationCursor,
376    NotFound,
377    NotUnique,
378}
379
380impl fmt::Debug for QueryErrorKind {
381    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
382        fmt_compact_code(f, *self as u16)
383    }
384}
385
386///
387/// QueryProjectionCode
388///
389/// Compact query projection admission/runtime identifier.
390/// Variant order is wire-order significant for public error-code offsets.
391///
392
393#[repr(u16)]
394#[derive(Clone, Copy, Eq, Hash, PartialEq)]
395pub enum QueryProjectionCode {
396    NumericLiteralRequired,
397    NumericScaleArguments,
398    NestedFieldPathPreview,
399    CaseConditionBooleanRequired,
400    NumericInputRequired,
401    TextOrBlobInputRequired,
402    TextInputRequired,
403    TextOrNullArgumentRequired,
404    IntegerOrNullArgumentRequired,
405    UnaryOperandIncompatible,
406    BinaryOperandsIncompatible,
407}
408
409impl fmt::Debug for QueryProjectionCode {
410    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
411        fmt_compact_code(f, *self as u16)
412    }
413}
414
415///
416/// QueryReadAdmissionCode
417///
418/// Compact read-admission rejection identifier.
419/// Variant order is wire-order significant for public error-code offsets.
420///
421
422#[repr(u16)]
423#[derive(Clone, Copy, Eq, Hash, PartialEq)]
424pub enum QueryReadAdmissionCode {
425    PublicQueryRequiresLimit,
426    PublicQueryRequiresIndex,
427    UnboundedFullScanRejected,
428    SortRequiresMaterialization,
429    GroupedQueryRequiresLimits,
430    GroupedQueryExceedsBudget,
431    DiagnosticLaneDoesNotExecute,
432    ReturnedRowBoundExceedsPolicy,
433    PrimaryKeyInputExceedsPolicy,
434    /// Authored query expressions or values exceed the shared depth ceiling.
435    InputDepthExceeded,
436    /// Authored query components exceed the shared node ceiling.
437    InputNodesExceeded,
438    /// Authored query payload exceeds the shared byte ceiling.
439    InputBytesExceeded,
440    /// Logical explain describes a request before any cursor boundary.
441    ExplainDoesNotAcceptCursor,
442}
443
444impl fmt::Debug for QueryReadAdmissionCode {
445    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
446        fmt_compact_code(f, *self as u16)
447    }
448}
449
450///
451/// RuntimeErrorKind
452///
453/// Public runtime error category.
454///
455
456#[repr(u16)]
457#[derive(Clone, Copy, Eq, Hash, PartialEq)]
458pub enum RuntimeErrorKind {
459    Corruption,
460    IncompatiblePersistedFormat,
461    InvariantViolation,
462    Conflict,
463    NotFound,
464    Unsupported,
465    Internal,
466}
467
468impl fmt::Debug for RuntimeErrorKind {
469    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
470        fmt_compact_code(f, *self as u16)
471    }
472}
473
474///
475/// RuntimeBoundaryCode
476///
477/// Compact public-runtime boundary identifier.
478/// Variant order is wire-order significant for public error-code offsets.
479///
480
481#[repr(u16)]
482#[derive(Clone, Copy, Eq, Hash, PartialEq)]
483pub enum RuntimeBoundaryCode {
484    SqlSurfaceControllerRequired,
485    SchemaSurfaceControllerRequired,
486    SqlQueryNoConfiguredEntities,
487    SqlQueryEntityNotFound,
488    SqlDdlTargetRequired,
489    SqlDdlEntityNotConfigured,
490    SqlIntrospectionDisabled,
491    /// A complete accepted mutation omitted a required field.
492    MutationRequiredFieldMissing,
493    /// A logical write would move an accepted managed timestamp backward.
494    MutationManagedTimestampRegression,
495    /// A persisted row's stamp falls outside the accepted layout window.
496    PersistedRowLayoutOutsideAcceptedWindow,
497    /// A persisted row's physical slot count disagrees with its layout stamp.
498    PersistedRowSlotCountMismatch,
499    /// A generated field would collide with an accepted DDL-owned slot.
500    GeneratedFieldAfterDdlField,
501    /// A journaled mutation cannot reserve a representable post-commit revision.
502    JournalMutationRevisionExhausted,
503    /// A final canonical after-image violates one accepted row constraint or gate.
504    ConstraintViolation,
505    /// Accepted row-constraint metadata or its compiled program is inconsistent.
506    AcceptedRowConstraintProgramCorrupt,
507    /// A write conflicts with one incomplete accepted constraint activation.
508    ConstraintActivationWriteBlocked,
509    /// A live generated constraint activation no longer matches its proposal.
510    GeneratedConstraintActivationStale,
511    /// A caller explicitly authored a field owned by accepted database policy.
512    MutationDatabaseOwnedFieldExplicit,
513    /// A mixed structural mutation batch contained no operations.
514    MutationBatchEmpty,
515    /// A mixed structural mutation batch exceeded its operation-count bound.
516    MutationBatchTooManyItems,
517    /// A mixed structural mutation batch exceeded its staged-byte bound.
518    MutationBatchStagedBytesExceeded,
519    /// A mixed structural mutation result exceeded its encoded response bound.
520    MutationBatchResultBytesExceeded,
521    /// A mixed structural mutation batch crossed an accepted store boundary.
522    MutationBatchStoreMismatch,
523    /// A mixed structural mutation batch exceeded its distinct-entity bound.
524    MutationBatchTooManyEntities,
525    /// More than one mixed structural operation targeted the same accepted key.
526    MutationBatchDuplicateKey,
527    /// An operational report or reset endpoint requires a controller caller.
528    OperationalSurfaceControllerRequired,
529    /// An exact-key batch exceeded its admitted input item count.
530    ExactKeyBatchTooManyItems,
531    /// An exact-key batch exceeded its admitted encoded input-key bytes.
532    ExactKeyBatchInputBytesExceeded,
533    /// An exact-key batch exceeded its admitted distinct stored-row bytes.
534    ExactKeyBatchStoredBytesExceeded,
535    /// An exact-key batch exceeded its admitted logical result bytes.
536    ExactKeyBatchResultBytesExceeded,
537    /// One charged execution resource exceeded its absolute safety ceiling.
538    ExecutionBudgetExceeded,
539    /// One indivisible scalar-page unit cannot fit in an otherwise empty page envelope.
540    PageUnitTooLarge,
541    /// Database access was attempted without an active request-execution scope.
542    RequestExecutionScopeRequired,
543    /// An explicit request root conflicts with the root already active for this request.
544    RequestExecutionRootMismatch,
545    /// A successful generated SQL query reply exceeds the deployed IC query-response limit.
546    SqlQueryReplyBytesExceeded,
547    QueryExplainOutputExceeded,
548    /// A derived logical explain access tree exceeds the diagnostic depth limit.
549    QueryExplainDepthExceeded,
550    /// Startup recovery remains incomplete and ordinary database work must retry later.
551    DatabaseStartupRecoveryPending,
552    /// An application guard denied access to the generated SQL read surface.
553    SqlSurfacePolicyDenied,
554    /// An application guard denied access to the generated accepted-schema surface.
555    SchemaSurfacePolicyDenied,
556    /// A structural mutation batch exceeded its canonical prepared-commit work bound.
557    MutationBatchCommitWorkExceeded,
558    /// Retained journal debt leaves insufficient bounded convergence capacity.
559    ConvergenceBacklogPressure,
560    /// Requested manager bucket pages differ from the existing memory layout.
561    MemoryBucketSizeMismatch,
562    /// Host grants cannot resolve or authorize current logical allocations.
563    MemoryAllocationResolutionFailed,
564    /// Current declarations omitted a historical IcyDB database namespace.
565    MemoryNamespaceRemoved,
566    /// Current database controls or store allocations lack a complete role set.
567    MemoryAllocationRolesIncomplete,
568    /// Current memory declarations violate their bounded identity/role contract.
569    MemoryDeclarationInvalid,
570    /// Current declaration requirements differ from established memory authority.
571    MemoryDeclarationSnapshotMismatch,
572    /// A historical allocation required for journal recovery cannot be selected.
573    MemoryHistoricalJournalUnavailable,
574    /// A typed batch handle belongs to another result owner.
575    TypedAdapterBatchHandleMismatch,
576    /// A typed batch result row has already been consumed.
577    TypedAdapterBatchRowConsumed,
578    /// Generated source descriptors cannot bind to accepted schema authority.
579    TypedAdapterBindingUnavailable,
580    /// The output row belongs to another accepted entity.
581    TypedAdapterEntityMismatch,
582    /// The requested immutable field source is absent from the binding.
583    TypedAdapterFieldUnavailable,
584    /// A generated field contract disagrees with accepted schema authority.
585    TypedAdapterIncompatibleField,
586    /// A projected output row omits the field needed by its typed adapter.
587    TypedAdapterRowFieldUnavailable,
588    /// Output column and value cardinalities disagree.
589    TypedAdapterRowShapeMismatch,
590    /// A typed binding no longer represents current accepted authority.
591    TypedAdapterStaleBinding,
592    /// An output value cannot be represented by the generated Rust field type.
593    TypedAdapterValueShapeMismatch,
594    /// A successful accepted-schema report exceeds the IC query reply byte cap.
595    SchemaReplyBytesExceeded,
596}
597
598impl fmt::Debug for RuntimeBoundaryCode {
599    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
600        fmt_compact_code(f, *self as u16)
601    }
602}
603
604///
605/// SqlFeatureCode
606///
607/// Compact SQL feature identifier used by unsupported-feature diagnostics.
608/// Variant order is wire-order significant for public error-code offsets.
609///
610
611#[repr(u16)]
612#[derive(Clone, Copy, Eq, Hash, PartialEq)]
613pub enum SqlFeatureCode {
614    AggregateFilterClause,
615    AlterStatementBeyondAlterTable,
616    AlterTableAddColumnDuplicateDefault,
617    AlterTableAddColumnModifiers,
618    AlterTableAddStatementBeyondAddColumn,
619    AlterTableAlterColumnDropUnsupportedAction,
620    AlterTableAlterColumnModifiers,
621    AlterTableAlterColumnSetUnsupportedAction,
622    AlterTableAlterColumnUnsupportedAction,
623    AlterTableAlterStatementBeyondAlterColumn,
624    AlterTableDropColumnIfExistsSyntax,
625    AlterTableDropColumnModifiers,
626    AlterTableDropStatementBeyondDropColumn,
627    AlterTableRenameColumnMissingTo,
628    AlterTableRenameColumnModifiers,
629    AlterTableRenameStatementBeyondRenameColumn,
630    AlterTableUnsupportedOperation,
631    ColumnAlias,
632    CreateIndexIfNotExistsSyntax,
633    CreateIndexKeyOrderingModifiers,
634    CreateIndexModifiers,
635    CreateStatementBeyondCreateIndex,
636    DescribeModifier,
637    DdlSchemaVersionDuplicateExpectedClause,
638    DdlSchemaVersionDuplicateSetClause,
639    DropIndexModifiers,
640    DropIndexIfExistsSyntax,
641    DropStatementBeyondDropIndex,
642    ExpressionIndexUnsupportedFunction,
643    Having,
644    Insert,
645    Join,
646    LikePatternBeyondTrailingPrefix,
647    LowerFieldPredicateUnsupported,
648    MultiStatementSql,
649    NestedAggregateInput,
650    NestedProjectionFunctionInArithmetic,
651    OrderByUnsupportedForm,
652    Other,
653    PredicateStartsWithFirstArgument,
654    QuotedIdentifiers,
655    ReturningUnsupportedShape,
656    ScalarFunctionExpressionPosition,
657    ScaleTakingNumericFunctionExpressionPosition,
658    ShowColumnsModifiers,
659    ShowEntitiesModifiers,
660    ShowIndexesModifiers,
661    ShowMemoryModifiers,
662    ShowStoresModifiers,
663    ShowUnsupportedCommand,
664    SimpleCaseExpression,
665    StandaloneLiteralProjectionItem,
666    UnionIntersectExcept,
667    UnsupportedFunctionNamespace,
668    Update,
669    UpperFieldPredicateUnsupported,
670    WindowFunction,
671    With,
672    NumericScaleFunctionArguments,
673    OrderByFieldNotOrderable,
674    ShowConstraintsModifiers,
675    AlterTableAddConstraintBeyondCheck,
676    AlterTableAddConstraintModifiers,
677    AlterTableDropConstraintIfExistsSyntax,
678    AlterTableDropConstraintModifiers,
679    AlterTableValidateBeyondConstraint,
680    AlterTableValidateConstraintModifiers,
681    ShowRelationsModifiers,
682}
683
684impl fmt::Debug for SqlFeatureCode {
685    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
686        fmt_compact_code(f, *self as u16)
687    }
688}
689
690///
691/// SqlLoweringCode
692///
693/// Compact SQL lowering rejection identifier used after parsing succeeds but
694/// before a statement becomes canonical query intent.
695/// Variant order is wire-order significant for public error-code offsets.
696///
697
698#[repr(u16)]
699#[derive(Clone, Copy, Eq, Hash, PartialEq)]
700pub enum SqlLoweringCode {
701    EntityMismatch,
702    SelectProjectionShape,
703    SelectDistinct,
704    DistinctOrderByProjection,
705    GlobalAggregateProjection,
706    GlobalAggregateGroupBy,
707    SelectGroupByShape,
708    GroupedProjectionExplicitListRequired,
709    GroupedProjectionAggregateRequired,
710    GroupedProjectionNonGroupField,
711    GroupedProjectionScalarAfterAggregate,
712    HavingRequiresGroupBy,
713    SelectHavingShape,
714    AggregateInputExpressions,
715    WhereExpressionShape,
716    ParameterPlacement,
717    SqlDdlExecutionUnsupported,
718    BindingCount,
719    BindingFamily,
720    BindingLimit,
721}
722
723impl fmt::Debug for SqlLoweringCode {
724    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
725        fmt_compact_code(f, *self as u16)
726    }
727}
728
729///
730/// SqlSurfaceMismatchCode
731///
732/// Compact SQL endpoint surface mismatch identifier.
733/// Variant order is wire-order significant for public error-code offsets.
734///
735
736#[repr(u16)]
737#[derive(Clone, Copy, Eq, Hash, PartialEq)]
738pub enum SqlSurfaceMismatchCode {
739    QueryRejectsInsert,
740    QueryRejectsUpdate,
741    QueryRejectsDelete,
742    MutationRejectsSelect,
743    MutationRejectsExplain,
744    MutationRejectsDescribe,
745    MutationRejectsShowIndexes,
746    MutationRejectsShowColumns,
747    MutationRejectsShowEntities,
748    MutationRejectsShowStores,
749    MutationRejectsShowMemory,
750    MutationRequiresExplicitUpdateIntent,
751    MutationRejectsShowConstraints,
752    MutationRejectsShowRelations,
753}
754
755impl fmt::Debug for SqlSurfaceMismatchCode {
756    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
757        fmt_compact_code(f, *self as u16)
758    }
759}
760
761///
762/// SqlWriteBoundaryCode
763///
764/// Compact SQL write fail-closed boundary identifier.
765/// Variant order is wire-order significant for public error-code offsets.
766///
767
768#[repr(u16)]
769#[derive(Clone, Copy, Eq, Hash, PartialEq)]
770pub enum SqlWriteBoundaryCode {
771    PrimaryKeyLiteralIncompatible,
772    MissingPrimaryKey,
773    MissingRequiredFields,
774    ExplicitManagedField,
775    ExplicitGeneratedField,
776    InsertSelectRequiresScalar,
777    InsertSelectAggregateProjection,
778    InsertSelectWidthMismatch,
779    UpdatePrimaryKeyMutation,
780    InvalidFieldLiteral,
781    UnknownReturningField,
782    DuplicateReturningField,
783    UpdateMissingWherePredicate,
784    WriteOrderByUnsupportedShape,
785    ReturningResponseTooLarge,
786    ReturningRowsTooMany,
787    StagedRowsTooMany,
788    InsertDefaultRequiredField,
789    UpdateDefaultRequiredField,
790    UpdateDefaultDatabaseOwnedField,
791    ExactUpdateAssertionRequired,
792    ExactUpdateAssertionTooHigh,
793    ExactUpdateAffectedRowsExceeded,
794    ExactUpdateWindowUnsupported,
795    WriteScanBudgetExceeded,
796    ResumableUpdateWindowUnsupported,
797    ResumableUpdateReturningUnsupported,
798    ResumableUpdateExpressionUnsupported,
799    ResumableUpdateRequiresJournaledStore,
800    ResumableUpdateAssignedFieldHasGlobalConstraint,
801    ResumableUpdateScopeDependsOnAssignedField,
802    ResumableUpdateScopeDependencyUnknown,
803    ResumableUpdateContinuationMalformed,
804    ResumableUpdateContinuationTargetMismatch,
805    ResumableUpdateContinuationSchemaMismatch,
806    ResumableUpdateContinuationScopeMismatch,
807    ResumableUpdateContinuationPatchMismatch,
808    ResumableUpdateContinuationBatchPolicyMismatch,
809    ResumableUpdateManagedFieldHasGlobalConstraint,
810}
811
812impl fmt::Debug for SqlWriteBoundaryCode {
813    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
814        fmt_compact_code(f, *self as u16)
815    }
816}
817
818///
819/// SchemaDdlAdmissionCode
820///
821/// Compact SQL DDL admission rejection reason.
822/// Variant order is wire-order significant for public error-code offsets.
823///
824
825#[repr(u16)]
826#[derive(Clone, Copy, Eq, Hash, PartialEq)]
827pub enum SchemaDdlAdmissionCode {
828    MissingExpectedSchemaVersion,
829    MissingNextSchemaVersion,
830    StaleExpectedSchemaVersion,
831    InvalidExpectedSchemaVersion,
832    InvalidNextSchemaVersion,
833    AcceptedSchemaChangeWithoutVersionBump,
834    EmptyVersionBump,
835    VersionGap,
836    VersionRollback,
837    FingerprintMethodMismatch,
838    UnsupportedTransitionClass,
839    PhysicalRunnerMissing,
840    ValidationFailed,
841    PublicationRaceLost,
842    InvalidAddColumnDefault,
843    InvalidAlterColumnDefault,
844    GeneratedIndexDropRejected,
845    SchemaRewriteRequiresMigration,
846    SchemaTransitionBudgetExceeded,
847    GeneratedFieldDefaultChangeRejected,
848    GeneratedFieldNullabilityChangeRejected,
849    RowLayoutVersionExhausted,
850}
851
852impl fmt::Debug for SchemaDdlAdmissionCode {
853    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
854        fmt_compact_code(f, *self as u16)
855    }
856}
857
858/// Machine-readable source-migration rejection or lifecycle finding.
859#[repr(u16)]
860#[derive(Clone, Copy, Eq, Hash, PartialEq)]
861pub enum SchemaMigrationCode {
862    Unadopted,
863    MissingMigration,
864    VersionGap,
865    Downgrade,
866    EmptyEntityVersionBump,
867    StaleAcceptedHead,
868    PlanChanged,
869    UnknownFromObject,
870    UnknownToObject,
871    KindMismatch,
872    IdentityConflict,
873    UnexplainedSchemaDifference,
874    UnsupportedTransform,
875    PhysicalRunnerMissing,
876    MigrationInProgress,
877    AbortTooLate,
878    ProgressCorrupt,
879    CandidateMismatch,
880    PublicationRaceLost,
881}
882
883impl SchemaMigrationCode {
884    /// Return the broad diagnostic category for this migration result.
885    #[must_use]
886    pub const fn diagnostic_code(self) -> DiagnosticCode {
887        match self {
888            Self::StaleAcceptedHead
889            | Self::PlanChanged
890            | Self::IdentityConflict
891            | Self::MigrationInProgress
892            | Self::AbortTooLate
893            | Self::PublicationRaceLost => DiagnosticCode::RuntimeConflict,
894            Self::ProgressCorrupt | Self::CandidateMismatch => DiagnosticCode::RuntimeCorruption,
895            Self::Unadopted
896            | Self::MissingMigration
897            | Self::VersionGap
898            | Self::Downgrade
899            | Self::EmptyEntityVersionBump
900            | Self::UnknownFromObject
901            | Self::UnknownToObject
902            | Self::KindMismatch
903            | Self::UnexplainedSchemaDifference
904            | Self::UnsupportedTransform
905            | Self::PhysicalRunnerMissing => DiagnosticCode::RuntimeUnsupported,
906        }
907    }
908}
909
910impl fmt::Debug for SchemaMigrationCode {
911    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
912        fmt_compact_code(f, *self as u16)
913    }
914}
915
916///
917/// DiagnosticDetail
918///
919/// Small structured diagnostic payload for callers and CLI rendering.
920///
921
922#[remain::sorted]
923#[derive(Clone, Copy, Eq, PartialEq)]
924pub enum DiagnosticDetail {
925    QueryKind { kind: QueryErrorKind },
926    QueryProjection { reason: QueryProjectionCode },
927    QueryReadAdmission { reason: QueryReadAdmissionCode },
928    RuntimeBoundary { boundary: RuntimeBoundaryCode },
929    RuntimeKind { kind: RuntimeErrorKind },
930    SchemaDdlAdmission { reason: SchemaDdlAdmissionCode },
931    SchemaMigration { reason: SchemaMigrationCode },
932    SqlLowering { reason: SqlLoweringCode },
933    SqlSurfaceMismatch { mismatch: SqlSurfaceMismatchCode },
934    SqlWriteBoundary { boundary: SqlWriteBoundaryCode },
935    UnsupportedSqlFeature { feature: SqlFeatureCode },
936}
937
938impl fmt::Debug for DiagnosticDetail {
939    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
940        fmt_compact_code(
941            f,
942            ErrorCode::from_parts(self.diagnostic_code(), Some(*self)).raw(),
943        )
944    }
945}
946
947///
948/// Diagnostic
949///
950/// Compact public diagnostic payload.
951///
952
953#[derive(Clone, Eq, PartialEq)]
954pub struct Diagnostic {
955    code: DiagnosticCode,
956    origin: ErrorOrigin,
957    detail: Option<DiagnosticDetail>,
958}
959
960impl Diagnostic {
961    /// Build a compact diagnostic from a code and optional structured detail.
962    #[must_use]
963    pub const fn new(
964        code: DiagnosticCode,
965        origin: ErrorOrigin,
966        detail: Option<DiagnosticDetail>,
967    ) -> Self {
968        Self {
969            code,
970            origin,
971            detail,
972        }
973    }
974
975    /// Build a compact diagnostic using the code's default origin.
976    #[must_use]
977    pub const fn from_code(code: DiagnosticCode) -> Self {
978        Self::new(code, code.origin(), None)
979    }
980
981    /// Return the stable diagnostic code.
982    #[must_use]
983    pub const fn code(&self) -> DiagnosticCode {
984        self.code
985    }
986
987    /// Return the diagnostic class.
988    #[must_use]
989    pub const fn class(&self) -> ErrorClass {
990        self.code.class()
991    }
992
993    /// Return the subsystem origin.
994    #[must_use]
995    pub const fn origin(&self) -> ErrorOrigin {
996        self.origin
997    }
998
999    /// Return structured diagnostic detail, when available.
1000    #[must_use]
1001    pub const fn detail(&self) -> Option<&DiagnosticDetail> {
1002        self.detail.as_ref()
1003    }
1004
1005    /// Return the numeric public wire code for this diagnostic.
1006    #[must_use]
1007    pub const fn error_code(&self) -> ErrorCode {
1008        ErrorCode::from_parts(self.code, self.detail)
1009    }
1010}
1011
1012impl fmt::Debug for Diagnostic {
1013    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1014        write!(f, "{}@{}", self.error_code().raw(), self.origin.wire_code())
1015    }
1016}
1017
1018fn fmt_compact_code(f: &mut fmt::Formatter<'_>, raw: u16) -> fmt::Result {
1019    write!(f, "{raw}")
1020}
1021
1022#[cfg(test)]
1023mod tests {
1024    use super::{
1025        Diagnostic, DiagnosticCode, DiagnosticDetail, ErrorClass, ErrorCode, ErrorOrigin,
1026        QueryProjectionCode, QueryReadAdmissionCode, SqlFeatureCode, SqlLoweringCode,
1027        SqlWriteBoundaryCode,
1028        registry::{DETAIL_ERROR_CODES, ORDERED_ERROR_CODES},
1029    };
1030
1031    #[test]
1032    fn diagnostic_from_code_uses_default_origin() {
1033        let diagnostic = Diagnostic::from_code(DiagnosticCode::QueryPlan);
1034
1035        assert_eq!(diagnostic.code(), DiagnosticCode::QueryPlan);
1036        assert_eq!(diagnostic.origin(), ErrorOrigin::Query);
1037    }
1038
1039    #[test]
1040    fn diagnostic_code_reports_broad_class() {
1041        assert_eq!(
1042            DiagnosticCode::QueryUnsupportedSqlFeature.class(),
1043            ErrorClass::Unsupported
1044        );
1045        assert_eq!(
1046            DiagnosticCode::QuerySqlSurfaceMismatch.class(),
1047            ErrorClass::Unsupported
1048        );
1049        assert_eq!(DiagnosticCode::QueryPlan.class(), ErrorClass::Query);
1050        assert_eq!(
1051            DiagnosticCode::StoreCorruption.class(),
1052            ErrorClass::Corruption
1053        );
1054    }
1055
1056    #[test]
1057    fn class_and_origin_wire_codes_round_trip() {
1058        for (class, raw) in [
1059            (ErrorClass::Query, 1),
1060            (ErrorClass::Corruption, 2),
1061            (ErrorClass::IncompatiblePersistedFormat, 3),
1062            (ErrorClass::NotFound, 4),
1063            (ErrorClass::Internal, 5),
1064            (ErrorClass::Conflict, 6),
1065            (ErrorClass::Unsupported, 7),
1066            (ErrorClass::InvariantViolation, 8),
1067        ] {
1068            assert_eq!(class.wire_code(), raw);
1069            assert_eq!(ErrorClass::from_wire_code(raw), Some(class));
1070            assert_eq!(format!("{class:?}"), raw.to_string());
1071        }
1072
1073        for (origin, raw) in [
1074            (ErrorOrigin::Cursor, 1),
1075            (ErrorOrigin::Executor, 2),
1076            (ErrorOrigin::Identity, 3),
1077            (ErrorOrigin::Index, 4),
1078            (ErrorOrigin::Interface, 5),
1079            (ErrorOrigin::Planner, 6),
1080            (ErrorOrigin::Query, 7),
1081            (ErrorOrigin::Recovery, 8),
1082            (ErrorOrigin::Response, 9),
1083            (ErrorOrigin::Runtime, 10),
1084            (ErrorOrigin::Serialize, 11),
1085            (ErrorOrigin::Store, 12),
1086        ] {
1087            assert_eq!(origin.wire_code(), raw);
1088            assert_eq!(ErrorOrigin::from_known_wire_code(raw), Some(origin));
1089            assert_eq!(ErrorOrigin::from_wire_code(raw), origin);
1090            assert_eq!(format!("{origin:?}"), raw.to_string());
1091        }
1092
1093        assert_eq!(ErrorClass::from_wire_code(0), None);
1094        assert_eq!(ErrorOrigin::from_known_wire_code(0), None);
1095        assert_eq!(ErrorOrigin::from_wire_code(0), ErrorOrigin::Runtime);
1096    }
1097
1098    #[test]
1099    fn public_error_codes_are_sequential() {
1100        let first = ORDERED_ERROR_CODES
1101            .first()
1102            .expect("public error-code registry is non-empty")
1103            .raw();
1104
1105        assert_eq!(first, 1);
1106
1107        for (index, code) in ORDERED_ERROR_CODES.iter().enumerate() {
1108            let expected = first + u16::try_from(index).expect("test error-code index fits u16");
1109            assert_eq!(code.raw(), expected);
1110            assert_eq!(ErrorCode::known(code.raw()), Some(*code));
1111            assert!(code.is_known());
1112        }
1113
1114        let last = ORDERED_ERROR_CODES
1115            .last()
1116            .expect("public error-code registry is non-empty")
1117            .raw();
1118
1119        assert_eq!(last, 293);
1120    }
1121
1122    #[test]
1123    fn all_public_error_codes_round_trip_through_diagnostic_parts() {
1124        let first = ORDERED_ERROR_CODES
1125            .first()
1126            .expect("public error-code registry is non-empty")
1127            .raw();
1128        let last = ORDERED_ERROR_CODES
1129            .last()
1130            .expect("public error-code registry is non-empty")
1131            .raw();
1132
1133        for raw in first..=last {
1134            let code = ErrorCode::from_raw(raw);
1135            let diagnostic_code = code.diagnostic_code();
1136            let diagnostic_detail = code.diagnostic_detail();
1137            let rebuilt = ErrorCode::from_parts(diagnostic_code, diagnostic_detail);
1138
1139            assert_eq!(rebuilt.raw(), raw);
1140
1141            let diagnostic = code.diagnostic(ErrorOrigin::Runtime);
1142
1143            assert_eq!(diagnostic.code(), diagnostic_code);
1144            assert_eq!(diagnostic.detail(), diagnostic_detail.as_ref());
1145            assert_eq!(diagnostic.error_code().raw(), raw);
1146        }
1147    }
1148
1149    #[test]
1150    fn invalid_raw_error_codes_fail_closed_to_runtime_internal() {
1151        let first_unknown = ORDERED_ERROR_CODES
1152            .last()
1153            .expect("public error-code registry is non-empty")
1154            .raw()
1155            .checked_add(1)
1156            .expect("public error-code registry retains an unknown successor");
1157
1158        for raw in [0, first_unknown, u16::MAX] {
1159            let code = ErrorCode::from_raw(raw);
1160
1161            assert_eq!(ErrorCode::known(raw), None);
1162            assert!(!code.is_known());
1163            assert_eq!(code.diagnostic_code(), DiagnosticCode::RuntimeInternal);
1164            assert_eq!(code.diagnostic_detail(), None);
1165            assert_eq!(code.class(), ErrorClass::Internal);
1166
1167            let diagnostic = code.diagnostic(ErrorOrigin::Query);
1168
1169            assert_eq!(diagnostic.code(), DiagnosticCode::RuntimeInternal);
1170            assert_eq!(diagnostic.origin(), ErrorOrigin::Query);
1171            assert_eq!(diagnostic.detail(), None);
1172            assert_eq!(diagnostic.error_code(), ErrorCode::RUNTIME_INTERNAL);
1173        }
1174    }
1175
1176    #[test]
1177    fn from_parts_requires_detail_to_match_broad_code() {
1178        let detail = Some(DiagnosticDetail::UnsupportedSqlFeature {
1179            feature: SqlFeatureCode::Join,
1180        });
1181
1182        assert_eq!(
1183            ErrorCode::from_parts(DiagnosticCode::QueryUnsupportedSqlFeature, detail),
1184            ErrorCode::SQL_FEATURE_JOIN
1185        );
1186        assert_eq!(
1187            ErrorCode::from_parts(DiagnosticCode::QueryPlan, detail),
1188            ErrorCode::QUERY_PLAN
1189        );
1190    }
1191
1192    #[test]
1193    fn detail_bearing_registry_entries_round_trip_directly() {
1194        assert!(!DETAIL_ERROR_CODES.is_empty());
1195
1196        for &(code, diagnostic_code, detail) in DETAIL_ERROR_CODES {
1197            assert_eq!(ErrorCode::from_parts(diagnostic_code, Some(detail)), code);
1198            assert_eq!(code.diagnostic_code(), diagnostic_code);
1199            assert_eq!(code.diagnostic_detail(), Some(detail));
1200            assert_eq!(detail.diagnostic_code(), diagnostic_code);
1201        }
1202    }
1203
1204    #[test]
1205    fn diagnostic_detail_reports_generated_broad_code() {
1206        let detail = DiagnosticDetail::UnsupportedSqlFeature {
1207            feature: SqlFeatureCode::Join,
1208        };
1209
1210        assert_eq!(
1211            detail.diagnostic_code(),
1212            DiagnosticCode::QueryUnsupportedSqlFeature
1213        );
1214        assert_eq!(format!("{detail:?}"), "61");
1215    }
1216
1217    #[test]
1218    fn public_error_codes_reconstruct_shifted_details() {
1219        assert_eq!(
1220            ErrorCode::QUERY_UNKNOWN_AGGREGATE_TARGET_FIELD.diagnostic_code(),
1221            DiagnosticCode::QueryUnknownAggregateTargetField
1222        );
1223        assert_eq!(
1224            ErrorCode::SQL_FEATURE_JOIN.diagnostic_detail(),
1225            Some(DiagnosticDetail::UnsupportedSqlFeature {
1226                feature: SqlFeatureCode::Join,
1227            })
1228        );
1229        assert_eq!(
1230            ErrorCode::QUERY_PROJECTION_NUMERIC_LITERAL_REQUIRED.diagnostic_detail(),
1231            Some(DiagnosticDetail::QueryProjection {
1232                reason: QueryProjectionCode::NumericLiteralRequired,
1233            })
1234        );
1235        assert_eq!(
1236            ErrorCode::QUERY_READ_PUBLIC_REQUIRES_LIMIT.diagnostic_detail(),
1237            Some(DiagnosticDetail::QueryReadAdmission {
1238                reason: QueryReadAdmissionCode::PublicQueryRequiresLimit,
1239            })
1240        );
1241        assert_eq!(
1242            ErrorCode::SQL_LOWERING_DISTINCT_ORDER_BY_PROJECTION.diagnostic_detail(),
1243            Some(DiagnosticDetail::SqlLowering {
1244                reason: SqlLoweringCode::DistinctOrderByProjection,
1245            })
1246        );
1247        assert_eq!(
1248            ErrorCode::SQL_WRITE_RETURNING_RESPONSE_TOO_LARGE.diagnostic_detail(),
1249            Some(DiagnosticDetail::SqlWriteBoundary {
1250                boundary: SqlWriteBoundaryCode::ReturningResponseTooLarge,
1251            })
1252        );
1253        assert_eq!(
1254            ErrorCode::SQL_WRITE_RETURNING_ROWS_TOO_MANY.diagnostic_detail(),
1255            Some(DiagnosticDetail::SqlWriteBoundary {
1256                boundary: SqlWriteBoundaryCode::ReturningRowsTooMany,
1257            })
1258        );
1259    }
1260}