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#[repr(u16)]
791#[derive(Clone, Copy, Eq, Hash, PartialEq)]
792pub enum SchemaMigrationCode {
793 Unadopted,
794 MissingMigration,
795 VersionGap,
796 Downgrade,
797 EmptyEntityVersionBump,
798 DuplicateEntityTransition,
799 StaleAcceptedHead,
800 PlanChanged,
801 DuplicateRenameSource,
802 DuplicateRenameTarget,
803 UnknownFromObject,
804 UnknownToObject,
805 KindMismatch,
806 IdentityConflict,
807 IncompleteRenameCoverage,
808 UnexplainedSchemaDifference,
809 UnsupportedTransform,
810 TransformFinding,
811 UniqueIndexFinding,
812 RelationFinding,
813 ConstraintFinding,
814 PhysicalRunnerMissing,
815 MigrationInProgress,
816 AbortTooLate,
817 ProgressCorrupt,
818 CandidateMismatch,
819 PublicationRaceLost,
820}
821
822impl SchemaMigrationCode {
823 #[must_use]
825 pub const fn diagnostic_code(self) -> DiagnosticCode {
826 match self {
827 Self::StaleAcceptedHead
828 | Self::PlanChanged
829 | Self::IdentityConflict
830 | Self::MigrationInProgress
831 | Self::AbortTooLate
832 | Self::PublicationRaceLost => DiagnosticCode::RuntimeConflict,
833 Self::ProgressCorrupt | Self::CandidateMismatch => DiagnosticCode::RuntimeCorruption,
834 Self::Unadopted
835 | Self::MissingMigration
836 | Self::VersionGap
837 | Self::Downgrade
838 | Self::EmptyEntityVersionBump
839 | Self::DuplicateEntityTransition
840 | Self::DuplicateRenameSource
841 | Self::DuplicateRenameTarget
842 | Self::UnknownFromObject
843 | Self::UnknownToObject
844 | Self::KindMismatch
845 | Self::IncompleteRenameCoverage
846 | Self::UnexplainedSchemaDifference
847 | Self::UnsupportedTransform
848 | Self::TransformFinding
849 | Self::UniqueIndexFinding
850 | Self::RelationFinding
851 | Self::ConstraintFinding
852 | Self::PhysicalRunnerMissing => DiagnosticCode::RuntimeUnsupported,
853 }
854 }
855}
856
857impl fmt::Debug for SchemaMigrationCode {
858 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
859 fmt_compact_code(f, *self as u16)
860 }
861}
862
863#[remain::sorted]
870#[derive(Clone, Copy, Eq, PartialEq)]
871pub enum DiagnosticDetail {
872 QueryKind { kind: QueryErrorKind },
873 QueryProjection { reason: QueryProjectionCode },
874 QueryReadAdmission { reason: QueryReadAdmissionCode },
875 QueryResultShape { reason: QueryResultShapeCode },
876 RuntimeBoundary { boundary: RuntimeBoundaryCode },
877 RuntimeKind { kind: RuntimeErrorKind },
878 SchemaDdlAdmission { reason: SchemaDdlAdmissionCode },
879 SchemaMigration { reason: SchemaMigrationCode },
880 SqlLowering { reason: SqlLoweringCode },
881 SqlSurfaceMismatch { mismatch: SqlSurfaceMismatchCode },
882 SqlWriteBoundary { boundary: SqlWriteBoundaryCode },
883 UnsupportedSqlFeature { feature: SqlFeatureCode },
884}
885
886impl fmt::Debug for DiagnosticDetail {
887 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
888 fmt_compact_code(
889 f,
890 ErrorCode::from_parts(self.diagnostic_code(), Some(*self)).raw(),
891 )
892 }
893}
894
895#[derive(Clone, Eq, PartialEq)]
902pub struct Diagnostic {
903 code: DiagnosticCode,
904 origin: ErrorOrigin,
905 detail: Option<DiagnosticDetail>,
906}
907
908impl Diagnostic {
909 #[must_use]
911 pub const fn new(
912 code: DiagnosticCode,
913 origin: ErrorOrigin,
914 detail: Option<DiagnosticDetail>,
915 ) -> Self {
916 Self {
917 code,
918 origin,
919 detail,
920 }
921 }
922
923 #[must_use]
925 pub const fn from_code(code: DiagnosticCode) -> Self {
926 Self::new(code, code.origin(), None)
927 }
928
929 #[must_use]
931 pub const fn code(&self) -> DiagnosticCode {
932 self.code
933 }
934
935 #[must_use]
937 pub const fn class(&self) -> ErrorClass {
938 self.code.class()
939 }
940
941 #[must_use]
943 pub const fn origin(&self) -> ErrorOrigin {
944 self.origin
945 }
946
947 #[must_use]
949 pub const fn detail(&self) -> Option<&DiagnosticDetail> {
950 self.detail.as_ref()
951 }
952
953 #[must_use]
955 pub const fn error_code(&self) -> ErrorCode {
956 ErrorCode::from_parts(self.code, self.detail)
957 }
958}
959
960impl fmt::Debug for Diagnostic {
961 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
962 write!(f, "{}@{}", self.error_code().raw(), self.origin.wire_code())
963 }
964}
965
966fn fmt_compact_code(f: &mut fmt::Formatter<'_>, raw: u16) -> fmt::Result {
967 write!(f, "{raw}")
968}
969
970#[cfg(test)]
971mod tests {
972 use super::{
973 Diagnostic, DiagnosticCode, DiagnosticDetail, ErrorClass, ErrorCode, ErrorOrigin,
974 QueryProjectionCode, QueryReadAdmissionCode, SqlFeatureCode, SqlLoweringCode,
975 SqlWriteBoundaryCode,
976 registry::{DETAIL_ERROR_CODES, ORDERED_ERROR_CODES},
977 };
978
979 #[test]
980 fn diagnostic_from_code_uses_default_origin() {
981 let diagnostic = Diagnostic::from_code(DiagnosticCode::QueryPlan);
982
983 assert_eq!(diagnostic.code(), DiagnosticCode::QueryPlan);
984 assert_eq!(diagnostic.origin(), ErrorOrigin::Query);
985 }
986
987 #[test]
988 fn diagnostic_code_reports_broad_class() {
989 assert_eq!(
990 DiagnosticCode::QueryUnsupportedSqlFeature.class(),
991 ErrorClass::Unsupported
992 );
993 assert_eq!(
994 DiagnosticCode::QuerySqlSurfaceMismatch.class(),
995 ErrorClass::Unsupported
996 );
997 assert_eq!(DiagnosticCode::QueryPlan.class(), ErrorClass::Query);
998 assert_eq!(
999 DiagnosticCode::StoreCorruption.class(),
1000 ErrorClass::Corruption
1001 );
1002 }
1003
1004 #[test]
1005 fn class_and_origin_wire_codes_round_trip() {
1006 for (class, raw) in [
1007 (ErrorClass::Query, 1),
1008 (ErrorClass::Corruption, 2),
1009 (ErrorClass::IncompatiblePersistedFormat, 3),
1010 (ErrorClass::NotFound, 4),
1011 (ErrorClass::Internal, 5),
1012 (ErrorClass::Conflict, 6),
1013 (ErrorClass::Unsupported, 7),
1014 (ErrorClass::InvariantViolation, 8),
1015 ] {
1016 assert_eq!(class.wire_code(), raw);
1017 assert_eq!(ErrorClass::from_wire_code(raw), Some(class));
1018 assert_eq!(format!("{class:?}"), raw.to_string());
1019 }
1020
1021 for (origin, raw) in [
1022 (ErrorOrigin::Cursor, 1),
1023 (ErrorOrigin::Executor, 2),
1024 (ErrorOrigin::Identity, 3),
1025 (ErrorOrigin::Index, 4),
1026 (ErrorOrigin::Interface, 5),
1027 (ErrorOrigin::Planner, 6),
1028 (ErrorOrigin::Query, 7),
1029 (ErrorOrigin::Recovery, 8),
1030 (ErrorOrigin::Response, 9),
1031 (ErrorOrigin::Runtime, 10),
1032 (ErrorOrigin::Serialize, 11),
1033 (ErrorOrigin::Store, 12),
1034 ] {
1035 assert_eq!(origin.wire_code(), raw);
1036 assert_eq!(ErrorOrigin::from_known_wire_code(raw), Some(origin));
1037 assert_eq!(ErrorOrigin::from_wire_code(raw), origin);
1038 assert_eq!(format!("{origin:?}"), raw.to_string());
1039 }
1040
1041 assert_eq!(ErrorClass::from_wire_code(0), None);
1042 assert_eq!(ErrorOrigin::from_known_wire_code(0), None);
1043 assert_eq!(ErrorOrigin::from_wire_code(0), ErrorOrigin::Runtime);
1044 }
1045
1046 #[test]
1047 fn public_error_codes_are_sequential() {
1048 let first = ORDERED_ERROR_CODES
1049 .first()
1050 .expect("public error-code registry is non-empty")
1051 .raw();
1052
1053 assert_eq!(first, 1);
1054
1055 for (index, code) in ORDERED_ERROR_CODES.iter().enumerate() {
1056 let expected = first + u16::try_from(index).expect("test error-code index fits u16");
1057 assert_eq!(code.raw(), expected);
1058 assert_eq!(ErrorCode::known(code.raw()), Some(*code));
1059 assert!(code.is_known());
1060 }
1061
1062 let last = ORDERED_ERROR_CODES
1063 .last()
1064 .expect("public error-code registry is non-empty")
1065 .raw();
1066
1067 assert_eq!(last, 268);
1068 }
1069
1070 #[test]
1071 fn all_public_error_codes_round_trip_through_diagnostic_parts() {
1072 let first = ORDERED_ERROR_CODES
1073 .first()
1074 .expect("public error-code registry is non-empty")
1075 .raw();
1076 let last = ORDERED_ERROR_CODES
1077 .last()
1078 .expect("public error-code registry is non-empty")
1079 .raw();
1080
1081 for raw in first..=last {
1082 let code = ErrorCode::from_raw(raw);
1083 let diagnostic_code = code.diagnostic_code();
1084 let diagnostic_detail = code.diagnostic_detail();
1085 let rebuilt = ErrorCode::from_parts(diagnostic_code, diagnostic_detail);
1086
1087 assert_eq!(rebuilt.raw(), raw);
1088
1089 let diagnostic = code.diagnostic(ErrorOrigin::Runtime);
1090
1091 assert_eq!(diagnostic.code(), diagnostic_code);
1092 assert_eq!(diagnostic.detail(), diagnostic_detail.as_ref());
1093 assert_eq!(diagnostic.error_code().raw(), raw);
1094 }
1095 }
1096
1097 #[test]
1098 fn invalid_raw_error_codes_fail_closed_to_runtime_internal() {
1099 for raw in [0, 269, u16::MAX] {
1100 let code = ErrorCode::from_raw(raw);
1101
1102 assert_eq!(ErrorCode::known(raw), None);
1103 assert!(!code.is_known());
1104 assert_eq!(code.diagnostic_code(), DiagnosticCode::RuntimeInternal);
1105 assert_eq!(code.diagnostic_detail(), None);
1106 assert_eq!(code.class(), ErrorClass::Internal);
1107
1108 let diagnostic = code.diagnostic(ErrorOrigin::Query);
1109
1110 assert_eq!(diagnostic.code(), DiagnosticCode::RuntimeInternal);
1111 assert_eq!(diagnostic.origin(), ErrorOrigin::Query);
1112 assert_eq!(diagnostic.detail(), None);
1113 assert_eq!(diagnostic.error_code(), ErrorCode::RUNTIME_INTERNAL);
1114 }
1115 }
1116
1117 #[test]
1118 fn from_parts_requires_detail_to_match_broad_code() {
1119 let detail = Some(DiagnosticDetail::UnsupportedSqlFeature {
1120 feature: SqlFeatureCode::Join,
1121 });
1122
1123 assert_eq!(
1124 ErrorCode::from_parts(DiagnosticCode::QueryUnsupportedSqlFeature, detail),
1125 ErrorCode::SQL_FEATURE_JOIN
1126 );
1127 assert_eq!(
1128 ErrorCode::from_parts(DiagnosticCode::QueryPlan, detail),
1129 ErrorCode::QUERY_PLAN
1130 );
1131 }
1132
1133 #[test]
1134 fn detail_bearing_registry_entries_round_trip_directly() {
1135 assert!(!DETAIL_ERROR_CODES.is_empty());
1136
1137 for &(code, diagnostic_code, detail) in DETAIL_ERROR_CODES {
1138 assert_eq!(ErrorCode::from_parts(diagnostic_code, Some(detail)), code);
1139 assert_eq!(code.diagnostic_code(), diagnostic_code);
1140 assert_eq!(code.diagnostic_detail(), Some(detail));
1141 assert_eq!(detail.diagnostic_code(), diagnostic_code);
1142 }
1143 }
1144
1145 #[test]
1146 fn diagnostic_detail_reports_generated_broad_code() {
1147 let detail = DiagnosticDetail::UnsupportedSqlFeature {
1148 feature: SqlFeatureCode::Join,
1149 };
1150
1151 assert_eq!(
1152 detail.diagnostic_code(),
1153 DiagnosticCode::QueryUnsupportedSqlFeature
1154 );
1155 assert_eq!(format!("{detail:?}"), "65");
1156 }
1157
1158 #[test]
1159 fn public_error_codes_reconstruct_shifted_details() {
1160 assert_eq!(
1161 ErrorCode::QUERY_UNKNOWN_AGGREGATE_TARGET_FIELD.diagnostic_code(),
1162 DiagnosticCode::QueryUnknownAggregateTargetField
1163 );
1164 assert_eq!(
1165 ErrorCode::SQL_FEATURE_JOIN.diagnostic_detail(),
1166 Some(DiagnosticDetail::UnsupportedSqlFeature {
1167 feature: SqlFeatureCode::Join,
1168 })
1169 );
1170 assert_eq!(
1171 ErrorCode::QUERY_PROJECTION_NUMERIC_LITERAL_REQUIRED.diagnostic_detail(),
1172 Some(DiagnosticDetail::QueryProjection {
1173 reason: QueryProjectionCode::NumericLiteralRequired,
1174 })
1175 );
1176 assert_eq!(
1177 ErrorCode::QUERY_READ_PUBLIC_REQUIRES_LIMIT.diagnostic_detail(),
1178 Some(DiagnosticDetail::QueryReadAdmission {
1179 reason: QueryReadAdmissionCode::PublicQueryRequiresLimit,
1180 })
1181 );
1182 assert_eq!(
1183 ErrorCode::SQL_LOWERING_DISTINCT_ORDER_BY_PROJECTION.diagnostic_detail(),
1184 Some(DiagnosticDetail::SqlLowering {
1185 reason: SqlLoweringCode::DistinctOrderByProjection,
1186 })
1187 );
1188 assert_eq!(
1189 ErrorCode::SQL_WRITE_RETURNING_RESPONSE_TOO_LARGE.diagnostic_detail(),
1190 Some(DiagnosticDetail::SqlWriteBoundary {
1191 boundary: SqlWriteBoundaryCode::ReturningResponseTooLarge,
1192 })
1193 );
1194 assert_eq!(
1195 ErrorCode::SQL_WRITE_RETURNING_ROWS_TOO_MANY.diagnostic_detail(),
1196 Some(DiagnosticDetail::SqlWriteBoundary {
1197 boundary: SqlWriteBoundaryCode::ReturningRowsTooMany,
1198 })
1199 );
1200 }
1201}