1use std::fmt;
13
14#[remain::sorted]
21#[derive(Clone, Copy, Eq, Hash, PartialEq)]
22pub enum DiagnosticCode {
23 QueryAccessRequirement,
24 QueryIntent,
25 QueryInvalidContinuationCursor,
26 QueryNotFound,
27 QueryNotUnique,
28 QueryNumericNotRepresentable,
29 QueryNumericOverflow,
30 QueryPlan,
31 QueryReadAdmission,
32 QueryResultShapeMismatch,
33 QuerySqlSurfaceMismatch,
34 QuerySqlWriteBoundary,
35 QueryUnknownAggregateTargetField,
36 QueryUnorderedPagination,
37 QueryUnsupportedProjection,
38 QueryUnsupportedSqlFeature,
39 QueryValidate,
40 RuntimeConflict,
41 RuntimeCorruption,
42 RuntimeIncompatiblePersistedFormat,
43 RuntimeInternal,
44 RuntimeInvariantViolation,
45 RuntimeNotFound,
46 RuntimeUnsupported,
47 SchemaDdlAdmission,
48 StoreCorruption,
49 StoreInvariantViolation,
50 StoreNotFound,
51}
52
53impl DiagnosticCode {
54 #[must_use]
56 pub const fn class(self) -> ErrorClass {
57 match self {
58 Self::StoreCorruption | Self::RuntimeCorruption => ErrorClass::Corruption,
59 Self::RuntimeIncompatiblePersistedFormat => ErrorClass::IncompatiblePersistedFormat,
60 Self::QueryNotFound | Self::StoreNotFound | Self::RuntimeNotFound => {
61 ErrorClass::NotFound
62 }
63 Self::RuntimeConflict => ErrorClass::Conflict,
64 Self::QueryUnsupportedSqlFeature
65 | Self::QueryUnknownAggregateTargetField
66 | Self::QueryUnsupportedProjection
67 | Self::QueryResultShapeMismatch
68 | Self::QuerySqlSurfaceMismatch
69 | Self::QuerySqlWriteBoundary
70 | Self::RuntimeUnsupported => ErrorClass::Unsupported,
71 Self::StoreInvariantViolation | Self::RuntimeInvariantViolation => {
72 ErrorClass::InvariantViolation
73 }
74 Self::RuntimeInternal => ErrorClass::Internal,
75 Self::QueryValidate
76 | Self::QueryIntent
77 | Self::QueryPlan
78 | Self::QueryReadAdmission
79 | Self::QueryAccessRequirement
80 | Self::QueryUnorderedPagination
81 | Self::QueryInvalidContinuationCursor
82 | Self::QueryNotUnique
83 | Self::QueryNumericOverflow
84 | Self::QueryNumericNotRepresentable
85 | Self::SchemaDdlAdmission => ErrorClass::Query,
86 }
87 }
88
89 #[must_use]
91 pub const fn origin(self) -> ErrorOrigin {
92 match self {
93 Self::StoreNotFound | Self::StoreCorruption | Self::StoreInvariantViolation => {
94 ErrorOrigin::Store
95 }
96 Self::RuntimeCorruption
97 | Self::RuntimeIncompatiblePersistedFormat
98 | Self::RuntimeInvariantViolation
99 | Self::RuntimeConflict
100 | Self::RuntimeNotFound
101 | Self::RuntimeUnsupported
102 | Self::RuntimeInternal => ErrorOrigin::Runtime,
103 Self::QueryValidate
104 | Self::QueryIntent
105 | Self::QueryPlan
106 | Self::QueryReadAdmission
107 | Self::QueryAccessRequirement
108 | Self::QueryUnorderedPagination
109 | Self::QueryInvalidContinuationCursor
110 | Self::QueryNotFound
111 | Self::QueryNotUnique
112 | Self::QueryNumericOverflow
113 | Self::QueryNumericNotRepresentable
114 | Self::QueryUnknownAggregateTargetField
115 | Self::QueryUnsupportedProjection
116 | Self::QueryResultShapeMismatch
117 | Self::QueryUnsupportedSqlFeature
118 | Self::QuerySqlSurfaceMismatch
119 | Self::QuerySqlWriteBoundary
120 | Self::SchemaDdlAdmission => ErrorOrigin::Query,
121 }
122 }
123
124 #[must_use]
126 pub const fn error_code(self) -> ErrorCode {
127 match self {
128 Self::QueryValidate => ErrorCode::QUERY_VALIDATE,
129 Self::QueryIntent => ErrorCode::QUERY_INTENT,
130 Self::QueryPlan => ErrorCode::QUERY_PLAN,
131 Self::QueryReadAdmission => ErrorCode::QUERY_READ_ADMISSION,
132 Self::QueryAccessRequirement => ErrorCode::QUERY_ACCESS_REQUIREMENT,
133 Self::QueryUnorderedPagination => ErrorCode::QUERY_UNORDERED_PAGINATION,
134 Self::QueryInvalidContinuationCursor => ErrorCode::QUERY_INVALID_CONTINUATION_CURSOR,
135 Self::QueryNotFound => ErrorCode::QUERY_NOT_FOUND,
136 Self::QueryNotUnique => ErrorCode::QUERY_NOT_UNIQUE,
137 Self::QueryNumericOverflow => ErrorCode::QUERY_NUMERIC_OVERFLOW,
138 Self::QueryNumericNotRepresentable => ErrorCode::QUERY_NUMERIC_NOT_REPRESENTABLE,
139 Self::QueryUnknownAggregateTargetField => {
140 ErrorCode::QUERY_UNKNOWN_AGGREGATE_TARGET_FIELD
141 }
142 Self::QueryUnsupportedProjection => ErrorCode::QUERY_UNSUPPORTED_PROJECTION,
143 Self::QueryResultShapeMismatch => ErrorCode::QUERY_RESULT_SHAPE_MISMATCH,
144 Self::QueryUnsupportedSqlFeature => ErrorCode::QUERY_UNSUPPORTED_SQL_FEATURE,
145 Self::QuerySqlSurfaceMismatch => ErrorCode::QUERY_SQL_SURFACE_MISMATCH,
146 Self::QuerySqlWriteBoundary => ErrorCode::QUERY_SQL_WRITE_BOUNDARY,
147 Self::SchemaDdlAdmission => ErrorCode::SCHEMA_DDL_ADMISSION,
148 Self::StoreNotFound => ErrorCode::STORE_NOT_FOUND,
149 Self::StoreCorruption => ErrorCode::STORE_CORRUPTION,
150 Self::StoreInvariantViolation => ErrorCode::STORE_INVARIANT_VIOLATION,
151 Self::RuntimeCorruption => ErrorCode::RUNTIME_CORRUPTION,
152 Self::RuntimeIncompatiblePersistedFormat => {
153 ErrorCode::RUNTIME_INCOMPATIBLE_PERSISTED_FORMAT
154 }
155 Self::RuntimeInvariantViolation => ErrorCode::RUNTIME_INVARIANT_VIOLATION,
156 Self::RuntimeConflict => ErrorCode::RUNTIME_CONFLICT,
157 Self::RuntimeNotFound => ErrorCode::RUNTIME_NOT_FOUND,
158 Self::RuntimeUnsupported => ErrorCode::RUNTIME_UNSUPPORTED,
159 Self::RuntimeInternal => ErrorCode::RUNTIME_INTERNAL,
160 }
161 }
162}
163
164impl fmt::Debug for DiagnosticCode {
165 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166 fmt_compact_code(f, self.error_code().raw())
167 }
168}
169
170#[derive(Clone, Copy, Eq, Hash, PartialEq)]
182pub struct ErrorCode(u16);
183
184mod registry;
185
186impl ErrorCode {
187 #[must_use]
189 pub const fn from_raw(raw: u16) -> Self {
190 Self(raw)
191 }
192
193 #[must_use]
195 pub const fn raw(self) -> u16 {
196 self.0
197 }
198}
199
200impl fmt::Debug for ErrorCode {
201 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202 fmt_compact_code(f, self.raw())
203 }
204}
205
206#[remain::sorted]
213#[derive(Clone, Copy, Eq, Hash, PartialEq)]
214pub enum ErrorClass {
215 Conflict,
216 Corruption,
217 IncompatiblePersistedFormat,
218 Internal,
219 InvariantViolation,
220 NotFound,
221 Query,
222 Unsupported,
223}
224
225impl ErrorClass {
226 #[must_use]
228 pub const fn wire_code(self) -> u8 {
229 match self {
230 Self::Query => 1,
231 Self::Corruption => 2,
232 Self::IncompatiblePersistedFormat => 3,
233 Self::NotFound => 4,
234 Self::Internal => 5,
235 Self::Conflict => 6,
236 Self::Unsupported => 7,
237 Self::InvariantViolation => 8,
238 }
239 }
240
241 #[must_use]
243 pub const fn from_wire_code(code: u8) -> Option<Self> {
244 match code {
245 1 => Some(Self::Query),
246 2 => Some(Self::Corruption),
247 3 => Some(Self::IncompatiblePersistedFormat),
248 4 => Some(Self::NotFound),
249 5 => Some(Self::Internal),
250 6 => Some(Self::Conflict),
251 7 => Some(Self::Unsupported),
252 8 => Some(Self::InvariantViolation),
253 _ => None,
254 }
255 }
256}
257
258impl fmt::Debug for ErrorClass {
259 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
260 fmt_compact_code(f, u16::from(self.wire_code()))
261 }
262}
263
264#[remain::sorted]
271#[derive(Clone, Copy, Eq, Hash, PartialEq)]
272pub enum ErrorOrigin {
273 Cursor,
274 Executor,
275 Identity,
276 Index,
277 Interface,
278 Planner,
279 Query,
280 Recovery,
281 Response,
282 Runtime,
283 Serialize,
284 Store,
285}
286
287impl ErrorOrigin {
288 #[must_use]
290 pub const fn wire_code(self) -> u8 {
291 match self {
292 Self::Cursor => 1,
293 Self::Executor => 2,
294 Self::Identity => 3,
295 Self::Index => 4,
296 Self::Interface => 5,
297 Self::Planner => 6,
298 Self::Query => 7,
299 Self::Recovery => 8,
300 Self::Response => 9,
301 Self::Runtime => 10,
302 Self::Serialize => 11,
303 Self::Store => 12,
304 }
305 }
306
307 #[must_use]
309 pub const fn from_known_wire_code(code: u8) -> Option<Self> {
310 match code {
311 1 => Some(Self::Cursor),
312 2 => Some(Self::Executor),
313 3 => Some(Self::Identity),
314 4 => Some(Self::Index),
315 5 => Some(Self::Interface),
316 6 => Some(Self::Planner),
317 7 => Some(Self::Query),
318 8 => Some(Self::Recovery),
319 9 => Some(Self::Response),
320 10 => Some(Self::Runtime),
321 11 => Some(Self::Serialize),
322 12 => Some(Self::Store),
323 _ => None,
324 }
325 }
326
327 #[must_use]
332 pub const fn from_wire_code(code: u8) -> Self {
333 match Self::from_known_wire_code(code) {
334 Some(origin) => origin,
335 None => Self::Runtime,
336 }
337 }
338}
339
340impl fmt::Debug for ErrorOrigin {
341 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
342 fmt_compact_code(f, u16::from(self.wire_code()))
343 }
344}
345
346#[repr(u16)]
353#[derive(Clone, Copy, Eq, Hash, PartialEq)]
354pub enum QueryErrorKind {
355 Validate,
356 Intent,
357 Plan,
358 AccessRequirement,
359 UnorderedPagination,
360 InvalidContinuationCursor,
361 NotFound,
362 NotUnique,
363}
364
365impl fmt::Debug for QueryErrorKind {
366 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
367 fmt_compact_code(f, *self as u16)
368 }
369}
370
371#[repr(u16)]
379#[derive(Clone, Copy, Eq, Hash, PartialEq)]
380pub enum QueryProjectionCode {
381 NumericLiteralRequired,
382 NumericScaleArguments,
383 NestedFieldPathPreview,
384 CaseConditionBooleanRequired,
385 NumericInputRequired,
386 TextOrBlobInputRequired,
387 TextInputRequired,
388 TextOrNullArgumentRequired,
389 IntegerOrNullArgumentRequired,
390 UnaryOperandIncompatible,
391 BinaryOperandsIncompatible,
392}
393
394impl fmt::Debug for QueryProjectionCode {
395 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
396 fmt_compact_code(f, *self as u16)
397 }
398}
399
400#[repr(u16)]
408#[derive(Clone, Copy, Eq, Hash, PartialEq)]
409pub enum QueryReadAdmissionCode {
410 PublicQueryRequiresLimit,
411 PublicQueryRequiresIndex,
412 UnboundedFullScanRejected,
413 SortRequiresMaterialization,
414 GroupedQueryRequiresLimits,
415 GroupedQueryExceedsBudget,
416 DiagnosticLaneDoesNotExecute,
417 ReturnedRowBoundExceedsPolicy,
418 PrimaryKeyInputExceedsPolicy,
419}
420
421impl fmt::Debug for QueryReadAdmissionCode {
422 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
423 fmt_compact_code(f, *self as u16)
424 }
425}
426
427#[repr(u16)]
435#[derive(Clone, Copy, Eq, Hash, PartialEq)]
436pub enum QueryResultShapeCode {
437 ExpectedRows,
438 ExpectedGroupedRows,
439}
440
441impl fmt::Debug for QueryResultShapeCode {
442 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
443 fmt_compact_code(f, *self as u16)
444 }
445}
446
447#[repr(u16)]
454#[derive(Clone, Copy, Eq, Hash, PartialEq)]
455pub enum RuntimeErrorKind {
456 Corruption,
457 IncompatiblePersistedFormat,
458 InvariantViolation,
459 Conflict,
460 NotFound,
461 Unsupported,
462 Internal,
463}
464
465impl fmt::Debug for RuntimeErrorKind {
466 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
467 fmt_compact_code(f, *self as u16)
468 }
469}
470
471#[repr(u16)]
479#[derive(Clone, Copy, Eq, Hash, PartialEq)]
480pub enum RuntimeBoundaryCode {
481 SqlSurfaceControllerRequired,
482 SchemaSurfaceControllerRequired,
483 SqlQueryNoConfiguredEntities,
484 SqlQueryEntityNotConfigured,
485 SqlDdlTargetRequired,
486 SqlDdlEntityNotConfigured,
487 QueryResponseRowsRequired,
488 QueryResponseGroupedRowsRequired,
489 RowProjectionFieldNotConfigured,
490 SqlIntrospectionDisabled,
491 MutationRequiredFieldMissing,
493 MutationManagedTimestampRegression,
495 PersistedRowLayoutOutsideAcceptedWindow,
497 PersistedRowSlotCountMismatch,
499 GeneratedFieldAfterDdlField,
501 JournalMutationRevisionExhausted,
503 ConstraintViolation,
505 AcceptedRowConstraintProgramCorrupt,
507 ConstraintActivationWriteBlocked,
509 GeneratedConstraintActivationStale,
511 MutationDatabaseOwnedFieldExplicit,
513 MutationBatchEmpty,
515 MutationBatchTooManyItems,
517 MutationBatchStagedBytesExceeded,
519 MutationBatchResultBytesExceeded,
521 MutationBatchEntityMismatch,
523 MutationBatchDuplicateKey,
525 OperationalSurfaceControllerRequired,
527}
528
529impl fmt::Debug for RuntimeBoundaryCode {
530 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
531 fmt_compact_code(f, *self as u16)
532 }
533}
534
535#[repr(u16)]
543#[derive(Clone, Copy, Eq, Hash, PartialEq)]
544pub enum SqlFeatureCode {
545 AggregateFilterClause,
546 AlterStatementBeyondAlterTable,
547 AlterTableAddColumnDuplicateDefault,
548 AlterTableAddColumnModifiers,
549 AlterTableAddStatementBeyondAddColumn,
550 AlterTableAlterColumnDropUnsupportedAction,
551 AlterTableAlterColumnModifiers,
552 AlterTableAlterColumnSetUnsupportedAction,
553 AlterTableAlterColumnUnsupportedAction,
554 AlterTableAlterStatementBeyondAlterColumn,
555 AlterTableDropColumnIfExistsSyntax,
556 AlterTableDropColumnModifiers,
557 AlterTableDropStatementBeyondDropColumn,
558 AlterTableRenameColumnMissingTo,
559 AlterTableRenameColumnModifiers,
560 AlterTableRenameStatementBeyondRenameColumn,
561 AlterTableUnsupportedOperation,
562 ColumnAlias,
563 CreateIndexIfNotExistsSyntax,
564 CreateIndexKeyOrderingModifiers,
565 CreateIndexModifiers,
566 CreateStatementBeyondCreateIndex,
567 DescribeModifier,
568 DdlSchemaVersionDuplicateExpectedClause,
569 DdlSchemaVersionDuplicateSetClause,
570 DropIndexModifiers,
571 DropIndexIfExistsSyntax,
572 DropStatementBeyondDropIndex,
573 ExpressionIndexUnsupportedFunction,
574 Having,
575 Insert,
576 Join,
577 LikePatternBeyondTrailingPrefix,
578 LowerFieldPredicateUnsupported,
579 MultiStatementSql,
580 NestedAggregateInput,
581 NestedProjectionFunctionInArithmetic,
582 OrderByUnsupportedForm,
583 Other,
584 PredicateStartsWithFirstArgument,
585 QuotedIdentifiers,
586 ReturningUnsupportedShape,
587 ScalarFunctionExpressionPosition,
588 ScaleTakingNumericFunctionExpressionPosition,
589 SearchedCaseGroupedOrderBy,
590 ShowColumnsModifiers,
591 ShowEntitiesModifiers,
592 ShowIndexesModifiers,
593 ShowMemoryModifiers,
594 ShowStoresModifiers,
595 ShowUnsupportedCommand,
596 SimpleCaseExpression,
597 StandaloneLiteralProjectionItem,
598 SupportedGroupedOrderByExpressionFamily,
599 SupportedOrderByExpressionFamily,
600 UnionIntersectExcept,
601 UnsupportedFunctionNamespace,
602 Update,
603 UpperFieldPredicateUnsupported,
604 WindowFunction,
605 With,
606 NumericScaleFunctionArguments,
607 OrderByFieldNotOrderable,
608 ShowConstraintsModifiers,
609 AlterTableAddConstraintBeyondCheck,
610 AlterTableAddConstraintModifiers,
611 AlterTableDropConstraintIfExistsSyntax,
612 AlterTableDropConstraintModifiers,
613 AlterTableValidateBeyondConstraint,
614 AlterTableValidateConstraintModifiers,
615}
616
617impl fmt::Debug for SqlFeatureCode {
618 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
619 fmt_compact_code(f, *self as u16)
620 }
621}
622
623#[repr(u16)]
632#[derive(Clone, Copy, Eq, Hash, PartialEq)]
633pub enum SqlLoweringCode {
634 EntityMismatch,
635 SelectProjectionShape,
636 SelectDistinct,
637 DistinctOrderByProjection,
638 GlobalAggregateProjection,
639 GlobalAggregateGroupBy,
640 SelectGroupByShape,
641 GroupedProjectionExplicitListRequired,
642 GroupedProjectionAggregateRequired,
643 GroupedProjectionNonGroupField,
644 GroupedProjectionScalarAfterAggregate,
645 HavingRequiresGroupBy,
646 SelectHavingShape,
647 AggregateInputExpressions,
648 WhereExpressionShape,
649 ParameterPlacement,
650 SqlDdlExecutionUnsupported,
651}
652
653impl fmt::Debug for SqlLoweringCode {
654 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
655 fmt_compact_code(f, *self as u16)
656 }
657}
658
659#[repr(u16)]
667#[derive(Clone, Copy, Eq, Hash, PartialEq)]
668pub enum SqlSurfaceMismatchCode {
669 QueryRejectsInsert,
670 QueryRejectsUpdate,
671 QueryRejectsDelete,
672 MutationRejectsSelect,
673 MutationRejectsExplain,
674 MutationRejectsDescribe,
675 MutationRejectsShowIndexes,
676 MutationRejectsShowColumns,
677 MutationRejectsShowEntities,
678 MutationRejectsShowStores,
679 MutationRejectsShowMemory,
680 MutationRequiresExplicitUpdateIntent,
681 MutationRejectsShowConstraints,
682}
683
684impl fmt::Debug for SqlSurfaceMismatchCode {
685 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
686 fmt_compact_code(f, *self as u16)
687 }
688}
689
690#[repr(u16)]
698#[derive(Clone, Copy, Eq, Hash, PartialEq)]
699pub enum SqlWriteBoundaryCode {
700 PrimaryKeyLiteralShape,
701 PrimaryKeyLiteralIncompatible,
702 MissingPrimaryKey,
703 MissingRequiredFields,
704 ExplicitManagedField,
705 ExplicitGeneratedField,
706 InsertSelectRequiresScalar,
707 InsertSelectAggregateProjection,
708 InsertSelectWidthMismatch,
709 UpdatePrimaryKeyMutation,
710 InvalidFieldLiteral,
711 UnknownReturningField,
712 DuplicateReturningField,
713 UpdateMissingWherePredicate,
714 WriteOrderByUnsupportedShape,
715 ReturningResponseTooLarge,
716 ReturningRowsTooMany,
717 StagedRowsTooMany,
718 InsertDefaultRequiredField,
719 UpdateDefaultRequiredField,
720 UpdateDefaultDatabaseOwnedField,
721 ExactUpdateAssertionRequired,
722 ExactUpdateAssertionTooHigh,
723 ExactUpdateAffectedRowsExceeded,
724 ExactUpdateWindowUnsupported,
725 ExactUpdateScanBudgetExceeded,
726 ResumableUpdateWindowUnsupported,
727 ResumableUpdateReturningUnsupported,
728 ResumableUpdateRequiresJournaledStore,
729 ResumableUpdateAssignedFieldHasGlobalConstraint,
730 ResumableUpdateScopeDependsOnAssignedField,
731 ResumableUpdateScopeDependencyUnknown,
732 ResumableUpdateContinuationMalformed,
733 ResumableUpdateContinuationTargetMismatch,
734 ResumableUpdateContinuationSchemaMismatch,
735 ResumableUpdateContinuationScopeMismatch,
736 ResumableUpdateContinuationPatchMismatch,
737 ResumableUpdateContinuationBatchPolicyMismatch,
738 ResumableUpdateSingleRowResourceExceeded,
739 ResumableUpdateManagedFieldHasGlobalConstraint,
740 ResumableUpdateContinuationOperationMismatch,
741}
742
743impl fmt::Debug for SqlWriteBoundaryCode {
744 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
745 fmt_compact_code(f, *self as u16)
746 }
747}
748
749#[repr(u16)]
757#[derive(Clone, Copy, Eq, Hash, PartialEq)]
758pub enum SchemaDdlAdmissionCode {
759 MissingExpectedSchemaVersion,
760 MissingNextSchemaVersion,
761 StaleExpectedSchemaVersion,
762 InvalidExpectedSchemaVersion,
763 InvalidNextSchemaVersion,
764 AcceptedSchemaChangeWithoutVersionBump,
765 EmptyVersionBump,
766 VersionGap,
767 VersionRollback,
768 FingerprintMethodMismatch,
769 UnsupportedTransitionClass,
770 PhysicalRunnerMissing,
771 ValidationFailed,
772 PublicationRaceLost,
773 InvalidAddColumnDefault,
774 InvalidAlterColumnDefault,
775 GeneratedIndexDropRejected,
776 SchemaRewriteRequiresMigration,
777 SchemaTransitionBudgetExceeded,
778 GeneratedFieldDefaultChangeRejected,
779 GeneratedFieldNullabilityChangeRejected,
780 RowLayoutVersionExhausted,
781}
782
783impl fmt::Debug for SchemaDdlAdmissionCode {
784 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
785 fmt_compact_code(f, *self as u16)
786 }
787}
788
789#[remain::sorted]
796#[derive(Clone, Copy, Eq, PartialEq)]
797pub enum DiagnosticDetail {
798 QueryKind { kind: QueryErrorKind },
799 QueryProjection { reason: QueryProjectionCode },
800 QueryReadAdmission { reason: QueryReadAdmissionCode },
801 QueryResultShape { reason: QueryResultShapeCode },
802 RuntimeBoundary { boundary: RuntimeBoundaryCode },
803 RuntimeKind { kind: RuntimeErrorKind },
804 SchemaDdlAdmission { reason: SchemaDdlAdmissionCode },
805 SqlLowering { reason: SqlLoweringCode },
806 SqlSurfaceMismatch { mismatch: SqlSurfaceMismatchCode },
807 SqlWriteBoundary { boundary: SqlWriteBoundaryCode },
808 UnsupportedSqlFeature { feature: SqlFeatureCode },
809}
810
811impl fmt::Debug for DiagnosticDetail {
812 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
813 fmt_compact_code(
814 f,
815 ErrorCode::from_parts(self.diagnostic_code(), Some(*self)).raw(),
816 )
817 }
818}
819
820#[derive(Clone, Eq, PartialEq)]
827pub struct Diagnostic {
828 code: DiagnosticCode,
829 origin: ErrorOrigin,
830 detail: Option<DiagnosticDetail>,
831}
832
833impl Diagnostic {
834 #[must_use]
836 pub const fn new(
837 code: DiagnosticCode,
838 origin: ErrorOrigin,
839 detail: Option<DiagnosticDetail>,
840 ) -> Self {
841 Self {
842 code,
843 origin,
844 detail,
845 }
846 }
847
848 #[must_use]
850 pub const fn from_code(code: DiagnosticCode) -> Self {
851 Self::new(code, code.origin(), None)
852 }
853
854 #[must_use]
856 pub const fn code(&self) -> DiagnosticCode {
857 self.code
858 }
859
860 #[must_use]
862 pub const fn class(&self) -> ErrorClass {
863 self.code.class()
864 }
865
866 #[must_use]
868 pub const fn origin(&self) -> ErrorOrigin {
869 self.origin
870 }
871
872 #[must_use]
874 pub const fn detail(&self) -> Option<&DiagnosticDetail> {
875 self.detail.as_ref()
876 }
877
878 #[must_use]
880 pub const fn error_code(&self) -> ErrorCode {
881 ErrorCode::from_parts(self.code, self.detail)
882 }
883}
884
885impl fmt::Debug for Diagnostic {
886 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
887 write!(f, "{}@{}", self.error_code().raw(), self.origin.wire_code())
888 }
889}
890
891fn fmt_compact_code(f: &mut fmt::Formatter<'_>, raw: u16) -> fmt::Result {
892 write!(f, "{raw}")
893}
894
895#[cfg(test)]
896mod tests {
897 use super::{
898 Diagnostic, DiagnosticCode, DiagnosticDetail, ErrorClass, ErrorCode, ErrorOrigin,
899 QueryProjectionCode, QueryReadAdmissionCode, SqlFeatureCode, SqlLoweringCode,
900 SqlWriteBoundaryCode,
901 registry::{DETAIL_ERROR_CODES, ORDERED_ERROR_CODES},
902 };
903
904 #[test]
905 fn diagnostic_from_code_uses_default_origin() {
906 let diagnostic = Diagnostic::from_code(DiagnosticCode::QueryPlan);
907
908 assert_eq!(diagnostic.code(), DiagnosticCode::QueryPlan);
909 assert_eq!(diagnostic.origin(), ErrorOrigin::Query);
910 }
911
912 #[test]
913 fn diagnostic_code_reports_broad_class() {
914 assert_eq!(
915 DiagnosticCode::QueryUnsupportedSqlFeature.class(),
916 ErrorClass::Unsupported
917 );
918 assert_eq!(
919 DiagnosticCode::QuerySqlSurfaceMismatch.class(),
920 ErrorClass::Unsupported
921 );
922 assert_eq!(DiagnosticCode::QueryPlan.class(), ErrorClass::Query);
923 assert_eq!(
924 DiagnosticCode::StoreCorruption.class(),
925 ErrorClass::Corruption
926 );
927 }
928
929 #[test]
930 fn class_and_origin_wire_codes_round_trip() {
931 for (class, raw) in [
932 (ErrorClass::Query, 1),
933 (ErrorClass::Corruption, 2),
934 (ErrorClass::IncompatiblePersistedFormat, 3),
935 (ErrorClass::NotFound, 4),
936 (ErrorClass::Internal, 5),
937 (ErrorClass::Conflict, 6),
938 (ErrorClass::Unsupported, 7),
939 (ErrorClass::InvariantViolation, 8),
940 ] {
941 assert_eq!(class.wire_code(), raw);
942 assert_eq!(ErrorClass::from_wire_code(raw), Some(class));
943 assert_eq!(format!("{class:?}"), raw.to_string());
944 }
945
946 for (origin, raw) in [
947 (ErrorOrigin::Cursor, 1),
948 (ErrorOrigin::Executor, 2),
949 (ErrorOrigin::Identity, 3),
950 (ErrorOrigin::Index, 4),
951 (ErrorOrigin::Interface, 5),
952 (ErrorOrigin::Planner, 6),
953 (ErrorOrigin::Query, 7),
954 (ErrorOrigin::Recovery, 8),
955 (ErrorOrigin::Response, 9),
956 (ErrorOrigin::Runtime, 10),
957 (ErrorOrigin::Serialize, 11),
958 (ErrorOrigin::Store, 12),
959 ] {
960 assert_eq!(origin.wire_code(), raw);
961 assert_eq!(ErrorOrigin::from_known_wire_code(raw), Some(origin));
962 assert_eq!(ErrorOrigin::from_wire_code(raw), origin);
963 assert_eq!(format!("{origin:?}"), raw.to_string());
964 }
965
966 assert_eq!(ErrorClass::from_wire_code(0), None);
967 assert_eq!(ErrorOrigin::from_known_wire_code(0), None);
968 assert_eq!(ErrorOrigin::from_wire_code(0), ErrorOrigin::Runtime);
969 }
970
971 #[test]
972 fn public_error_codes_are_sequential() {
973 let first = ORDERED_ERROR_CODES
974 .first()
975 .expect("public error-code registry is non-empty")
976 .raw();
977
978 assert_eq!(first, 1);
979
980 for (index, code) in ORDERED_ERROR_CODES.iter().enumerate() {
981 let expected = first + u16::try_from(index).expect("test error-code index fits u16");
982 assert_eq!(code.raw(), expected);
983 assert_eq!(ErrorCode::known(code.raw()), Some(*code));
984 assert!(code.is_known());
985 }
986
987 let last = ORDERED_ERROR_CODES
988 .last()
989 .expect("public error-code registry is non-empty")
990 .raw();
991
992 assert_eq!(last, 241);
993 }
994
995 #[test]
996 fn all_public_error_codes_round_trip_through_diagnostic_parts() {
997 let first = ORDERED_ERROR_CODES
998 .first()
999 .expect("public error-code registry is non-empty")
1000 .raw();
1001 let last = ORDERED_ERROR_CODES
1002 .last()
1003 .expect("public error-code registry is non-empty")
1004 .raw();
1005
1006 for raw in first..=last {
1007 let code = ErrorCode::from_raw(raw);
1008 let diagnostic_code = code.diagnostic_code();
1009 let diagnostic_detail = code.diagnostic_detail();
1010 let rebuilt = ErrorCode::from_parts(diagnostic_code, diagnostic_detail);
1011
1012 assert_eq!(rebuilt.raw(), raw);
1013
1014 let diagnostic = code.diagnostic(ErrorOrigin::Runtime);
1015
1016 assert_eq!(diagnostic.code(), diagnostic_code);
1017 assert_eq!(diagnostic.detail(), diagnostic_detail.as_ref());
1018 assert_eq!(diagnostic.error_code().raw(), raw);
1019 }
1020 }
1021
1022 #[test]
1023 fn invalid_raw_error_codes_fail_closed_to_runtime_internal() {
1024 for raw in [0, 242, u16::MAX] {
1025 let code = ErrorCode::from_raw(raw);
1026
1027 assert_eq!(ErrorCode::known(raw), None);
1028 assert!(!code.is_known());
1029 assert_eq!(code.diagnostic_code(), DiagnosticCode::RuntimeInternal);
1030 assert_eq!(code.diagnostic_detail(), None);
1031 assert_eq!(code.class(), ErrorClass::Internal);
1032
1033 let diagnostic = code.diagnostic(ErrorOrigin::Query);
1034
1035 assert_eq!(diagnostic.code(), DiagnosticCode::RuntimeInternal);
1036 assert_eq!(diagnostic.origin(), ErrorOrigin::Query);
1037 assert_eq!(diagnostic.detail(), None);
1038 assert_eq!(diagnostic.error_code(), ErrorCode::RUNTIME_INTERNAL);
1039 }
1040 }
1041
1042 #[test]
1043 fn from_parts_requires_detail_to_match_broad_code() {
1044 let detail = Some(DiagnosticDetail::UnsupportedSqlFeature {
1045 feature: SqlFeatureCode::Join,
1046 });
1047
1048 assert_eq!(
1049 ErrorCode::from_parts(DiagnosticCode::QueryUnsupportedSqlFeature, detail),
1050 ErrorCode::SQL_FEATURE_JOIN
1051 );
1052 assert_eq!(
1053 ErrorCode::from_parts(DiagnosticCode::QueryPlan, detail),
1054 ErrorCode::QUERY_PLAN
1055 );
1056 }
1057
1058 #[test]
1059 fn detail_bearing_registry_entries_round_trip_directly() {
1060 assert!(!DETAIL_ERROR_CODES.is_empty());
1061
1062 for &(code, diagnostic_code, detail) in DETAIL_ERROR_CODES {
1063 assert_eq!(ErrorCode::from_parts(diagnostic_code, Some(detail)), code);
1064 assert_eq!(code.diagnostic_code(), diagnostic_code);
1065 assert_eq!(code.diagnostic_detail(), Some(detail));
1066 assert_eq!(detail.diagnostic_code(), diagnostic_code);
1067 }
1068 }
1069
1070 #[test]
1071 fn diagnostic_detail_reports_generated_broad_code() {
1072 let detail = DiagnosticDetail::UnsupportedSqlFeature {
1073 feature: SqlFeatureCode::Join,
1074 };
1075
1076 assert_eq!(
1077 detail.diagnostic_code(),
1078 DiagnosticCode::QueryUnsupportedSqlFeature
1079 );
1080 assert_eq!(format!("{detail:?}"), "65");
1081 }
1082
1083 #[test]
1084 fn public_error_codes_reconstruct_shifted_details() {
1085 assert_eq!(
1086 ErrorCode::QUERY_UNKNOWN_AGGREGATE_TARGET_FIELD.diagnostic_code(),
1087 DiagnosticCode::QueryUnknownAggregateTargetField
1088 );
1089 assert_eq!(
1090 ErrorCode::SQL_FEATURE_JOIN.diagnostic_detail(),
1091 Some(DiagnosticDetail::UnsupportedSqlFeature {
1092 feature: SqlFeatureCode::Join,
1093 })
1094 );
1095 assert_eq!(
1096 ErrorCode::QUERY_PROJECTION_NUMERIC_LITERAL_REQUIRED.diagnostic_detail(),
1097 Some(DiagnosticDetail::QueryProjection {
1098 reason: QueryProjectionCode::NumericLiteralRequired,
1099 })
1100 );
1101 assert_eq!(
1102 ErrorCode::QUERY_READ_PUBLIC_REQUIRES_LIMIT.diagnostic_detail(),
1103 Some(DiagnosticDetail::QueryReadAdmission {
1104 reason: QueryReadAdmissionCode::PublicQueryRequiresLimit,
1105 })
1106 );
1107 assert_eq!(
1108 ErrorCode::SQL_LOWERING_DISTINCT_ORDER_BY_PROJECTION.diagnostic_detail(),
1109 Some(DiagnosticDetail::SqlLowering {
1110 reason: SqlLoweringCode::DistinctOrderByProjection,
1111 })
1112 );
1113 assert_eq!(
1114 ErrorCode::SQL_WRITE_RETURNING_RESPONSE_TOO_LARGE.diagnostic_detail(),
1115 Some(DiagnosticDetail::SqlWriteBoundary {
1116 boundary: SqlWriteBoundaryCode::ReturningResponseTooLarge,
1117 })
1118 );
1119 assert_eq!(
1120 ErrorCode::SQL_WRITE_RETURNING_ROWS_TOO_MANY.diagnostic_detail(),
1121 Some(DiagnosticDetail::SqlWriteBoundary {
1122 boundary: SqlWriteBoundaryCode::ReturningRowsTooMany,
1123 })
1124 );
1125 }
1126}