1use std::fmt;
13
14mod fact;
15
16pub use fact::{
17 DiagnosticAggregateKind, DiagnosticComponentKind, DiagnosticConstraintContext,
18 DiagnosticConstraintKind, DiagnosticDecodeReason, DiagnosticFactSchemaMismatch,
19 DiagnosticFactTag, DiagnosticFunctionKind, DiagnosticMutationOperation, DiagnosticOperatorKind,
20 DiagnosticTypeFamily, MAX_PUBLIC_DIAGNOSTIC_FACTS, pack_u32_pair, unpack_u32_pair,
21 validate_known_diagnostic_fact_schema, validate_raw_diagnostic_fact_schema,
22};
23
24#[remain::sorted]
31#[derive(Clone, Copy, Eq, Hash, PartialEq)]
32pub enum DiagnosticCode {
33 QueryAccessRequirement,
34 QueryIntent,
35 QueryInvalidContinuationCursor,
36 QueryNotFound,
37 QueryNotUnique,
38 QueryNumericNotRepresentable,
39 QueryNumericOverflow,
40 QueryPlan,
41 QueryReadAdmission,
42 QueryResultShapeMismatch,
43 QuerySqlSurfaceMismatch,
44 QuerySqlWriteBoundary,
45 QueryUnknownAggregateTargetField,
46 QueryUnorderedPagination,
47 QueryUnsupportedProjection,
48 QueryUnsupportedSqlFeature,
49 QueryValidate,
50 RuntimeConflict,
51 RuntimeCorruption,
52 RuntimeIncompatiblePersistedFormat,
53 RuntimeInternal,
54 RuntimeInvariantViolation,
55 RuntimeNotFound,
56 RuntimeUnsupported,
57 SchemaDdlAdmission,
58 StoreCorruption,
59 StoreInvariantViolation,
60 StoreNotFound,
61}
62
63impl DiagnosticCode {
64 #[must_use]
66 pub const fn class(self) -> ErrorClass {
67 match self {
68 Self::StoreCorruption | Self::RuntimeCorruption => ErrorClass::Corruption,
69 Self::RuntimeIncompatiblePersistedFormat => ErrorClass::IncompatiblePersistedFormat,
70 Self::QueryNotFound | Self::StoreNotFound | Self::RuntimeNotFound => {
71 ErrorClass::NotFound
72 }
73 Self::RuntimeConflict => ErrorClass::Conflict,
74 Self::QueryUnsupportedSqlFeature
75 | Self::QueryUnknownAggregateTargetField
76 | Self::QueryUnsupportedProjection
77 | Self::QueryResultShapeMismatch
78 | Self::QuerySqlSurfaceMismatch
79 | Self::QuerySqlWriteBoundary
80 | Self::RuntimeUnsupported => ErrorClass::Unsupported,
81 Self::StoreInvariantViolation | Self::RuntimeInvariantViolation => {
82 ErrorClass::InvariantViolation
83 }
84 Self::RuntimeInternal => ErrorClass::Internal,
85 Self::QueryValidate
86 | Self::QueryIntent
87 | Self::QueryPlan
88 | Self::QueryReadAdmission
89 | Self::QueryAccessRequirement
90 | Self::QueryUnorderedPagination
91 | Self::QueryInvalidContinuationCursor
92 | Self::QueryNotUnique
93 | Self::QueryNumericOverflow
94 | Self::QueryNumericNotRepresentable
95 | Self::SchemaDdlAdmission => ErrorClass::Query,
96 }
97 }
98
99 #[must_use]
101 pub const fn origin(self) -> ErrorOrigin {
102 match self {
103 Self::StoreNotFound | Self::StoreCorruption | Self::StoreInvariantViolation => {
104 ErrorOrigin::Store
105 }
106 Self::RuntimeCorruption
107 | Self::RuntimeIncompatiblePersistedFormat
108 | Self::RuntimeInvariantViolation
109 | Self::RuntimeConflict
110 | Self::RuntimeNotFound
111 | Self::RuntimeUnsupported
112 | Self::RuntimeInternal => ErrorOrigin::Runtime,
113 Self::QueryValidate
114 | Self::QueryIntent
115 | Self::QueryPlan
116 | Self::QueryReadAdmission
117 | Self::QueryAccessRequirement
118 | Self::QueryUnorderedPagination
119 | Self::QueryInvalidContinuationCursor
120 | Self::QueryNotFound
121 | Self::QueryNotUnique
122 | Self::QueryNumericOverflow
123 | Self::QueryNumericNotRepresentable
124 | Self::QueryUnknownAggregateTargetField
125 | Self::QueryUnsupportedProjection
126 | Self::QueryResultShapeMismatch
127 | Self::QueryUnsupportedSqlFeature
128 | Self::QuerySqlSurfaceMismatch
129 | Self::QuerySqlWriteBoundary
130 | Self::SchemaDdlAdmission => ErrorOrigin::Query,
131 }
132 }
133
134 #[must_use]
136 pub const fn error_code(self) -> ErrorCode {
137 match self {
138 Self::QueryValidate => ErrorCode::QUERY_VALIDATE,
139 Self::QueryIntent => ErrorCode::QUERY_INTENT,
140 Self::QueryPlan => ErrorCode::QUERY_PLAN,
141 Self::QueryReadAdmission => ErrorCode::QUERY_READ_ADMISSION,
142 Self::QueryAccessRequirement => ErrorCode::QUERY_ACCESS_REQUIREMENT,
143 Self::QueryUnorderedPagination => ErrorCode::QUERY_UNORDERED_PAGINATION,
144 Self::QueryInvalidContinuationCursor => ErrorCode::QUERY_INVALID_CONTINUATION_CURSOR,
145 Self::QueryNotFound => ErrorCode::QUERY_NOT_FOUND,
146 Self::QueryNotUnique => ErrorCode::QUERY_NOT_UNIQUE,
147 Self::QueryNumericOverflow => ErrorCode::QUERY_NUMERIC_OVERFLOW,
148 Self::QueryNumericNotRepresentable => ErrorCode::QUERY_NUMERIC_NOT_REPRESENTABLE,
149 Self::QueryUnknownAggregateTargetField => {
150 ErrorCode::QUERY_UNKNOWN_AGGREGATE_TARGET_FIELD
151 }
152 Self::QueryUnsupportedProjection => ErrorCode::QUERY_UNSUPPORTED_PROJECTION,
153 Self::QueryResultShapeMismatch => ErrorCode::QUERY_RESULT_SHAPE_MISMATCH,
154 Self::QueryUnsupportedSqlFeature => ErrorCode::QUERY_UNSUPPORTED_SQL_FEATURE,
155 Self::QuerySqlSurfaceMismatch => ErrorCode::QUERY_SQL_SURFACE_MISMATCH,
156 Self::QuerySqlWriteBoundary => ErrorCode::QUERY_SQL_WRITE_BOUNDARY,
157 Self::SchemaDdlAdmission => ErrorCode::SCHEMA_DDL_ADMISSION,
158 Self::StoreNotFound => ErrorCode::STORE_NOT_FOUND,
159 Self::StoreCorruption => ErrorCode::STORE_CORRUPTION,
160 Self::StoreInvariantViolation => ErrorCode::STORE_INVARIANT_VIOLATION,
161 Self::RuntimeCorruption => ErrorCode::RUNTIME_CORRUPTION,
162 Self::RuntimeIncompatiblePersistedFormat => {
163 ErrorCode::RUNTIME_INCOMPATIBLE_PERSISTED_FORMAT
164 }
165 Self::RuntimeInvariantViolation => ErrorCode::RUNTIME_INVARIANT_VIOLATION,
166 Self::RuntimeConflict => ErrorCode::RUNTIME_CONFLICT,
167 Self::RuntimeNotFound => ErrorCode::RUNTIME_NOT_FOUND,
168 Self::RuntimeUnsupported => ErrorCode::RUNTIME_UNSUPPORTED,
169 Self::RuntimeInternal => ErrorCode::RUNTIME_INTERNAL,
170 }
171 }
172}
173
174impl fmt::Debug for DiagnosticCode {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 fmt_compact_code(f, self.error_code().raw())
177 }
178}
179
180#[derive(Clone, Copy, Eq, Hash, PartialEq)]
192pub struct ErrorCode(u16);
193
194mod registry;
195
196impl ErrorCode {
197 #[must_use]
199 pub const fn from_raw(raw: u16) -> Self {
200 Self(raw)
201 }
202
203 #[must_use]
205 pub const fn raw(self) -> u16 {
206 self.0
207 }
208}
209
210impl fmt::Debug for ErrorCode {
211 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212 fmt_compact_code(f, self.raw())
213 }
214}
215
216#[remain::sorted]
223#[derive(Clone, Copy, Eq, Hash, PartialEq)]
224pub enum ErrorClass {
225 Conflict,
226 Corruption,
227 IncompatiblePersistedFormat,
228 Internal,
229 InvariantViolation,
230 NotFound,
231 Query,
232 Unsupported,
233}
234
235impl ErrorClass {
236 #[must_use]
238 pub const fn wire_code(self) -> u8 {
239 match self {
240 Self::Query => 1,
241 Self::Corruption => 2,
242 Self::IncompatiblePersistedFormat => 3,
243 Self::NotFound => 4,
244 Self::Internal => 5,
245 Self::Conflict => 6,
246 Self::Unsupported => 7,
247 Self::InvariantViolation => 8,
248 }
249 }
250
251 #[must_use]
253 pub const fn from_wire_code(code: u8) -> Option<Self> {
254 match code {
255 1 => Some(Self::Query),
256 2 => Some(Self::Corruption),
257 3 => Some(Self::IncompatiblePersistedFormat),
258 4 => Some(Self::NotFound),
259 5 => Some(Self::Internal),
260 6 => Some(Self::Conflict),
261 7 => Some(Self::Unsupported),
262 8 => Some(Self::InvariantViolation),
263 _ => None,
264 }
265 }
266}
267
268impl fmt::Debug for ErrorClass {
269 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270 fmt_compact_code(f, u16::from(self.wire_code()))
271 }
272}
273
274#[remain::sorted]
281#[derive(Clone, Copy, Eq, Hash, PartialEq)]
282pub enum ErrorOrigin {
283 Cursor,
284 Executor,
285 Identity,
286 Index,
287 Interface,
288 Planner,
289 Query,
290 Recovery,
291 Response,
292 Runtime,
293 Serialize,
294 Store,
295}
296
297impl ErrorOrigin {
298 #[must_use]
300 pub const fn wire_code(self) -> u8 {
301 match self {
302 Self::Cursor => 1,
303 Self::Executor => 2,
304 Self::Identity => 3,
305 Self::Index => 4,
306 Self::Interface => 5,
307 Self::Planner => 6,
308 Self::Query => 7,
309 Self::Recovery => 8,
310 Self::Response => 9,
311 Self::Runtime => 10,
312 Self::Serialize => 11,
313 Self::Store => 12,
314 }
315 }
316
317 #[must_use]
319 pub const fn from_known_wire_code(code: u8) -> Option<Self> {
320 match code {
321 1 => Some(Self::Cursor),
322 2 => Some(Self::Executor),
323 3 => Some(Self::Identity),
324 4 => Some(Self::Index),
325 5 => Some(Self::Interface),
326 6 => Some(Self::Planner),
327 7 => Some(Self::Query),
328 8 => Some(Self::Recovery),
329 9 => Some(Self::Response),
330 10 => Some(Self::Runtime),
331 11 => Some(Self::Serialize),
332 12 => Some(Self::Store),
333 _ => None,
334 }
335 }
336
337 #[must_use]
342 pub const fn from_wire_code(code: u8) -> Self {
343 match Self::from_known_wire_code(code) {
344 Some(origin) => origin,
345 None => Self::Runtime,
346 }
347 }
348}
349
350impl fmt::Debug for ErrorOrigin {
351 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352 fmt_compact_code(f, u16::from(self.wire_code()))
353 }
354}
355
356#[repr(u16)]
363#[derive(Clone, Copy, Eq, Hash, PartialEq)]
364pub enum QueryErrorKind {
365 Validate,
366 Intent,
367 Plan,
368 AccessRequirement,
369 UnorderedPagination,
370 InvalidContinuationCursor,
371 NotFound,
372 NotUnique,
373}
374
375impl fmt::Debug for QueryErrorKind {
376 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
377 fmt_compact_code(f, *self as u16)
378 }
379}
380
381#[repr(u16)]
389#[derive(Clone, Copy, Eq, Hash, PartialEq)]
390pub enum QueryProjectionCode {
391 NumericLiteralRequired,
392 NumericScaleArguments,
393 NestedFieldPathPreview,
394 CaseConditionBooleanRequired,
395 NumericInputRequired,
396 TextOrBlobInputRequired,
397 TextInputRequired,
398 TextOrNullArgumentRequired,
399 IntegerOrNullArgumentRequired,
400 UnaryOperandIncompatible,
401 BinaryOperandsIncompatible,
402}
403
404impl fmt::Debug for QueryProjectionCode {
405 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406 fmt_compact_code(f, *self as u16)
407 }
408}
409
410#[repr(u16)]
418#[derive(Clone, Copy, Eq, Hash, PartialEq)]
419pub enum QueryReadAdmissionCode {
420 PublicQueryRequiresLimit,
421 PublicQueryRequiresIndex,
422 UnboundedFullScanRejected,
423 SortRequiresMaterialization,
424 GroupedQueryRequiresLimits,
425 GroupedQueryExceedsBudget,
426 DiagnosticLaneDoesNotExecute,
427 ReturnedRowBoundExceedsPolicy,
428 PrimaryKeyInputExceedsPolicy,
429}
430
431impl fmt::Debug for QueryReadAdmissionCode {
432 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
433 fmt_compact_code(f, *self as u16)
434 }
435}
436
437#[repr(u16)]
445#[derive(Clone, Copy, Eq, Hash, PartialEq)]
446pub enum QueryResultShapeCode {
447 ExpectedRows,
448 ExpectedGroupedRows,
449}
450
451impl fmt::Debug for QueryResultShapeCode {
452 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
453 fmt_compact_code(f, *self as u16)
454 }
455}
456
457#[repr(u16)]
464#[derive(Clone, Copy, Eq, Hash, PartialEq)]
465pub enum RuntimeErrorKind {
466 Corruption,
467 IncompatiblePersistedFormat,
468 InvariantViolation,
469 Conflict,
470 NotFound,
471 Unsupported,
472 Internal,
473}
474
475impl fmt::Debug for RuntimeErrorKind {
476 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
477 fmt_compact_code(f, *self as u16)
478 }
479}
480
481#[repr(u16)]
489#[derive(Clone, Copy, Eq, Hash, PartialEq)]
490pub enum RuntimeBoundaryCode {
491 SqlSurfaceControllerRequired,
492 SchemaSurfaceControllerRequired,
493 SqlQueryNoConfiguredEntities,
494 SqlQueryEntityNotConfigured,
495 SqlDdlTargetRequired,
496 SqlDdlEntityNotConfigured,
497 QueryResponseRowsRequired,
498 QueryResponseGroupedRowsRequired,
499 RowProjectionFieldNotConfigured,
500 SqlIntrospectionDisabled,
501 MutationRequiredFieldMissing,
503 MutationManagedTimestampRegression,
505 PersistedRowLayoutOutsideAcceptedWindow,
507 PersistedRowSlotCountMismatch,
509 GeneratedFieldAfterDdlField,
511 JournalMutationRevisionExhausted,
513 ConstraintViolation,
515 AcceptedRowConstraintProgramCorrupt,
517 ConstraintActivationWriteBlocked,
519 GeneratedConstraintActivationStale,
521 MutationDatabaseOwnedFieldExplicit,
523 MutationBatchEmpty,
525 MutationBatchTooManyItems,
527 MutationBatchStagedBytesExceeded,
529 MutationBatchResultBytesExceeded,
531 MutationBatchEntityMismatch,
533 MutationBatchDuplicateKey,
535 OperationalSurfaceControllerRequired,
537 ExactKeyBatchTooManyItems,
539 ExactKeyBatchInputBytesExceeded,
541 ExactKeyBatchStoredBytesExceeded,
543 ExactKeyBatchResultBytesExceeded,
545}
546
547impl fmt::Debug for RuntimeBoundaryCode {
548 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
549 fmt_compact_code(f, *self as u16)
550 }
551}
552
553#[repr(u16)]
561#[derive(Clone, Copy, Eq, Hash, PartialEq)]
562pub enum SqlFeatureCode {
563 AggregateFilterClause,
564 AlterStatementBeyondAlterTable,
565 AlterTableAddColumnDuplicateDefault,
566 AlterTableAddColumnModifiers,
567 AlterTableAddStatementBeyondAddColumn,
568 AlterTableAlterColumnDropUnsupportedAction,
569 AlterTableAlterColumnModifiers,
570 AlterTableAlterColumnSetUnsupportedAction,
571 AlterTableAlterColumnUnsupportedAction,
572 AlterTableAlterStatementBeyondAlterColumn,
573 AlterTableDropColumnIfExistsSyntax,
574 AlterTableDropColumnModifiers,
575 AlterTableDropStatementBeyondDropColumn,
576 AlterTableRenameColumnMissingTo,
577 AlterTableRenameColumnModifiers,
578 AlterTableRenameStatementBeyondRenameColumn,
579 AlterTableUnsupportedOperation,
580 ColumnAlias,
581 CreateIndexIfNotExistsSyntax,
582 CreateIndexKeyOrderingModifiers,
583 CreateIndexModifiers,
584 CreateStatementBeyondCreateIndex,
585 DescribeModifier,
586 DdlSchemaVersionDuplicateExpectedClause,
587 DdlSchemaVersionDuplicateSetClause,
588 DropIndexModifiers,
589 DropIndexIfExistsSyntax,
590 DropStatementBeyondDropIndex,
591 ExpressionIndexUnsupportedFunction,
592 Having,
593 Insert,
594 Join,
595 LikePatternBeyondTrailingPrefix,
596 LowerFieldPredicateUnsupported,
597 MultiStatementSql,
598 NestedAggregateInput,
599 NestedProjectionFunctionInArithmetic,
600 OrderByUnsupportedForm,
601 Other,
602 PredicateStartsWithFirstArgument,
603 QuotedIdentifiers,
604 ReturningUnsupportedShape,
605 ScalarFunctionExpressionPosition,
606 ScaleTakingNumericFunctionExpressionPosition,
607 SearchedCaseGroupedOrderBy,
608 ShowColumnsModifiers,
609 ShowEntitiesModifiers,
610 ShowIndexesModifiers,
611 ShowMemoryModifiers,
612 ShowStoresModifiers,
613 ShowUnsupportedCommand,
614 SimpleCaseExpression,
615 StandaloneLiteralProjectionItem,
616 SupportedGroupedOrderByExpressionFamily,
617 SupportedOrderByExpressionFamily,
618 UnionIntersectExcept,
619 UnsupportedFunctionNamespace,
620 Update,
621 UpperFieldPredicateUnsupported,
622 WindowFunction,
623 With,
624 NumericScaleFunctionArguments,
625 OrderByFieldNotOrderable,
626 ShowConstraintsModifiers,
627 AlterTableAddConstraintBeyondCheck,
628 AlterTableAddConstraintModifiers,
629 AlterTableDropConstraintIfExistsSyntax,
630 AlterTableDropConstraintModifiers,
631 AlterTableValidateBeyondConstraint,
632 AlterTableValidateConstraintModifiers,
633}
634
635impl fmt::Debug for SqlFeatureCode {
636 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
637 fmt_compact_code(f, *self as u16)
638 }
639}
640
641#[repr(u16)]
650#[derive(Clone, Copy, Eq, Hash, PartialEq)]
651pub enum SqlLoweringCode {
652 EntityMismatch,
653 SelectProjectionShape,
654 SelectDistinct,
655 DistinctOrderByProjection,
656 GlobalAggregateProjection,
657 GlobalAggregateGroupBy,
658 SelectGroupByShape,
659 GroupedProjectionExplicitListRequired,
660 GroupedProjectionAggregateRequired,
661 GroupedProjectionNonGroupField,
662 GroupedProjectionScalarAfterAggregate,
663 HavingRequiresGroupBy,
664 SelectHavingShape,
665 AggregateInputExpressions,
666 WhereExpressionShape,
667 ParameterPlacement,
668 SqlDdlExecutionUnsupported,
669}
670
671impl fmt::Debug for SqlLoweringCode {
672 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
673 fmt_compact_code(f, *self as u16)
674 }
675}
676
677#[repr(u16)]
685#[derive(Clone, Copy, Eq, Hash, PartialEq)]
686pub enum SqlSurfaceMismatchCode {
687 QueryRejectsInsert,
688 QueryRejectsUpdate,
689 QueryRejectsDelete,
690 MutationRejectsSelect,
691 MutationRejectsExplain,
692 MutationRejectsDescribe,
693 MutationRejectsShowIndexes,
694 MutationRejectsShowColumns,
695 MutationRejectsShowEntities,
696 MutationRejectsShowStores,
697 MutationRejectsShowMemory,
698 MutationRequiresExplicitUpdateIntent,
699 MutationRejectsShowConstraints,
700}
701
702impl fmt::Debug for SqlSurfaceMismatchCode {
703 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
704 fmt_compact_code(f, *self as u16)
705 }
706}
707
708#[repr(u16)]
716#[derive(Clone, Copy, Eq, Hash, PartialEq)]
717pub enum SqlWriteBoundaryCode {
718 PrimaryKeyLiteralShape,
719 PrimaryKeyLiteralIncompatible,
720 MissingPrimaryKey,
721 MissingRequiredFields,
722 ExplicitManagedField,
723 ExplicitGeneratedField,
724 InsertSelectRequiresScalar,
725 InsertSelectAggregateProjection,
726 InsertSelectWidthMismatch,
727 UpdatePrimaryKeyMutation,
728 InvalidFieldLiteral,
729 UnknownReturningField,
730 DuplicateReturningField,
731 UpdateMissingWherePredicate,
732 WriteOrderByUnsupportedShape,
733 ReturningResponseTooLarge,
734 ReturningRowsTooMany,
735 StagedRowsTooMany,
736 InsertDefaultRequiredField,
737 UpdateDefaultRequiredField,
738 UpdateDefaultDatabaseOwnedField,
739 ExactUpdateAssertionRequired,
740 ExactUpdateAssertionTooHigh,
741 ExactUpdateAffectedRowsExceeded,
742 ExactUpdateWindowUnsupported,
743 ExactUpdateScanBudgetExceeded,
744 ResumableUpdateWindowUnsupported,
745 ResumableUpdateReturningUnsupported,
746 ResumableUpdateRequiresJournaledStore,
747 ResumableUpdateAssignedFieldHasGlobalConstraint,
748 ResumableUpdateScopeDependsOnAssignedField,
749 ResumableUpdateScopeDependencyUnknown,
750 ResumableUpdateContinuationMalformed,
751 ResumableUpdateContinuationTargetMismatch,
752 ResumableUpdateContinuationSchemaMismatch,
753 ResumableUpdateContinuationScopeMismatch,
754 ResumableUpdateContinuationPatchMismatch,
755 ResumableUpdateContinuationBatchPolicyMismatch,
756 ResumableUpdateSingleRowResourceExceeded,
757 ResumableUpdateManagedFieldHasGlobalConstraint,
758 ResumableUpdateContinuationOperationMismatch,
759}
760
761impl fmt::Debug for SqlWriteBoundaryCode {
762 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
763 fmt_compact_code(f, *self as u16)
764 }
765}
766
767#[repr(u16)]
775#[derive(Clone, Copy, Eq, Hash, PartialEq)]
776pub enum SchemaDdlAdmissionCode {
777 MissingExpectedSchemaVersion,
778 MissingNextSchemaVersion,
779 StaleExpectedSchemaVersion,
780 InvalidExpectedSchemaVersion,
781 InvalidNextSchemaVersion,
782 AcceptedSchemaChangeWithoutVersionBump,
783 EmptyVersionBump,
784 VersionGap,
785 VersionRollback,
786 FingerprintMethodMismatch,
787 UnsupportedTransitionClass,
788 PhysicalRunnerMissing,
789 ValidationFailed,
790 PublicationRaceLost,
791 InvalidAddColumnDefault,
792 InvalidAlterColumnDefault,
793 GeneratedIndexDropRejected,
794 SchemaRewriteRequiresMigration,
795 SchemaTransitionBudgetExceeded,
796 GeneratedFieldDefaultChangeRejected,
797 GeneratedFieldNullabilityChangeRejected,
798 RowLayoutVersionExhausted,
799}
800
801impl fmt::Debug for SchemaDdlAdmissionCode {
802 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
803 fmt_compact_code(f, *self as u16)
804 }
805}
806
807#[repr(u16)]
809#[derive(Clone, Copy, Eq, Hash, PartialEq)]
810pub enum SchemaMigrationCode {
811 Unadopted,
812 MissingMigration,
813 VersionGap,
814 Downgrade,
815 EmptyEntityVersionBump,
816 DuplicateEntityTransition,
817 StaleAcceptedHead,
818 PlanChanged,
819 DuplicateRenameSource,
820 DuplicateRenameTarget,
821 UnknownFromObject,
822 UnknownToObject,
823 KindMismatch,
824 IdentityConflict,
825 IncompleteRenameCoverage,
826 UnexplainedSchemaDifference,
827 UnsupportedTransform,
828 TransformFinding,
829 UniqueIndexFinding,
830 RelationFinding,
831 ConstraintFinding,
832 PhysicalRunnerMissing,
833 MigrationInProgress,
834 AbortTooLate,
835 ProgressCorrupt,
836 CandidateMismatch,
837 PublicationRaceLost,
838}
839
840impl SchemaMigrationCode {
841 #[must_use]
843 pub const fn diagnostic_code(self) -> DiagnosticCode {
844 match self {
845 Self::StaleAcceptedHead
846 | Self::PlanChanged
847 | Self::IdentityConflict
848 | Self::MigrationInProgress
849 | Self::AbortTooLate
850 | Self::PublicationRaceLost => DiagnosticCode::RuntimeConflict,
851 Self::ProgressCorrupt | Self::CandidateMismatch => DiagnosticCode::RuntimeCorruption,
852 Self::Unadopted
853 | Self::MissingMigration
854 | Self::VersionGap
855 | Self::Downgrade
856 | Self::EmptyEntityVersionBump
857 | Self::DuplicateEntityTransition
858 | Self::DuplicateRenameSource
859 | Self::DuplicateRenameTarget
860 | Self::UnknownFromObject
861 | Self::UnknownToObject
862 | Self::KindMismatch
863 | Self::IncompleteRenameCoverage
864 | Self::UnexplainedSchemaDifference
865 | Self::UnsupportedTransform
866 | Self::TransformFinding
867 | Self::UniqueIndexFinding
868 | Self::RelationFinding
869 | Self::ConstraintFinding
870 | Self::PhysicalRunnerMissing => DiagnosticCode::RuntimeUnsupported,
871 }
872 }
873}
874
875impl fmt::Debug for SchemaMigrationCode {
876 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
877 fmt_compact_code(f, *self as u16)
878 }
879}
880
881#[remain::sorted]
888#[derive(Clone, Copy, Eq, PartialEq)]
889pub enum DiagnosticDetail {
890 QueryKind { kind: QueryErrorKind },
891 QueryProjection { reason: QueryProjectionCode },
892 QueryReadAdmission { reason: QueryReadAdmissionCode },
893 QueryResultShape { reason: QueryResultShapeCode },
894 RuntimeBoundary { boundary: RuntimeBoundaryCode },
895 RuntimeKind { kind: RuntimeErrorKind },
896 SchemaDdlAdmission { reason: SchemaDdlAdmissionCode },
897 SchemaMigration { reason: SchemaMigrationCode },
898 SqlLowering { reason: SqlLoweringCode },
899 SqlSurfaceMismatch { mismatch: SqlSurfaceMismatchCode },
900 SqlWriteBoundary { boundary: SqlWriteBoundaryCode },
901 UnsupportedSqlFeature { feature: SqlFeatureCode },
902}
903
904impl fmt::Debug for DiagnosticDetail {
905 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
906 fmt_compact_code(
907 f,
908 ErrorCode::from_parts(self.diagnostic_code(), Some(*self)).raw(),
909 )
910 }
911}
912
913#[derive(Clone, Eq, PartialEq)]
920pub struct Diagnostic {
921 code: DiagnosticCode,
922 origin: ErrorOrigin,
923 detail: Option<DiagnosticDetail>,
924}
925
926impl Diagnostic {
927 #[must_use]
929 pub const fn new(
930 code: DiagnosticCode,
931 origin: ErrorOrigin,
932 detail: Option<DiagnosticDetail>,
933 ) -> Self {
934 Self {
935 code,
936 origin,
937 detail,
938 }
939 }
940
941 #[must_use]
943 pub const fn from_code(code: DiagnosticCode) -> Self {
944 Self::new(code, code.origin(), None)
945 }
946
947 #[must_use]
949 pub const fn code(&self) -> DiagnosticCode {
950 self.code
951 }
952
953 #[must_use]
955 pub const fn class(&self) -> ErrorClass {
956 self.code.class()
957 }
958
959 #[must_use]
961 pub const fn origin(&self) -> ErrorOrigin {
962 self.origin
963 }
964
965 #[must_use]
967 pub const fn detail(&self) -> Option<&DiagnosticDetail> {
968 self.detail.as_ref()
969 }
970
971 #[must_use]
973 pub const fn error_code(&self) -> ErrorCode {
974 ErrorCode::from_parts(self.code, self.detail)
975 }
976}
977
978impl fmt::Debug for Diagnostic {
979 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
980 write!(f, "{}@{}", self.error_code().raw(), self.origin.wire_code())
981 }
982}
983
984fn fmt_compact_code(f: &mut fmt::Formatter<'_>, raw: u16) -> fmt::Result {
985 write!(f, "{raw}")
986}
987
988#[cfg(test)]
989mod tests {
990 use super::{
991 Diagnostic, DiagnosticCode, DiagnosticDetail, ErrorClass, ErrorCode, ErrorOrigin,
992 QueryProjectionCode, QueryReadAdmissionCode, SqlFeatureCode, SqlLoweringCode,
993 SqlWriteBoundaryCode,
994 registry::{DETAIL_ERROR_CODES, ORDERED_ERROR_CODES},
995 };
996
997 #[test]
998 fn diagnostic_from_code_uses_default_origin() {
999 let diagnostic = Diagnostic::from_code(DiagnosticCode::QueryPlan);
1000
1001 assert_eq!(diagnostic.code(), DiagnosticCode::QueryPlan);
1002 assert_eq!(diagnostic.origin(), ErrorOrigin::Query);
1003 }
1004
1005 #[test]
1006 fn diagnostic_code_reports_broad_class() {
1007 assert_eq!(
1008 DiagnosticCode::QueryUnsupportedSqlFeature.class(),
1009 ErrorClass::Unsupported
1010 );
1011 assert_eq!(
1012 DiagnosticCode::QuerySqlSurfaceMismatch.class(),
1013 ErrorClass::Unsupported
1014 );
1015 assert_eq!(DiagnosticCode::QueryPlan.class(), ErrorClass::Query);
1016 assert_eq!(
1017 DiagnosticCode::StoreCorruption.class(),
1018 ErrorClass::Corruption
1019 );
1020 }
1021
1022 #[test]
1023 fn class_and_origin_wire_codes_round_trip() {
1024 for (class, raw) in [
1025 (ErrorClass::Query, 1),
1026 (ErrorClass::Corruption, 2),
1027 (ErrorClass::IncompatiblePersistedFormat, 3),
1028 (ErrorClass::NotFound, 4),
1029 (ErrorClass::Internal, 5),
1030 (ErrorClass::Conflict, 6),
1031 (ErrorClass::Unsupported, 7),
1032 (ErrorClass::InvariantViolation, 8),
1033 ] {
1034 assert_eq!(class.wire_code(), raw);
1035 assert_eq!(ErrorClass::from_wire_code(raw), Some(class));
1036 assert_eq!(format!("{class:?}"), raw.to_string());
1037 }
1038
1039 for (origin, raw) in [
1040 (ErrorOrigin::Cursor, 1),
1041 (ErrorOrigin::Executor, 2),
1042 (ErrorOrigin::Identity, 3),
1043 (ErrorOrigin::Index, 4),
1044 (ErrorOrigin::Interface, 5),
1045 (ErrorOrigin::Planner, 6),
1046 (ErrorOrigin::Query, 7),
1047 (ErrorOrigin::Recovery, 8),
1048 (ErrorOrigin::Response, 9),
1049 (ErrorOrigin::Runtime, 10),
1050 (ErrorOrigin::Serialize, 11),
1051 (ErrorOrigin::Store, 12),
1052 ] {
1053 assert_eq!(origin.wire_code(), raw);
1054 assert_eq!(ErrorOrigin::from_known_wire_code(raw), Some(origin));
1055 assert_eq!(ErrorOrigin::from_wire_code(raw), origin);
1056 assert_eq!(format!("{origin:?}"), raw.to_string());
1057 }
1058
1059 assert_eq!(ErrorClass::from_wire_code(0), None);
1060 assert_eq!(ErrorOrigin::from_known_wire_code(0), None);
1061 assert_eq!(ErrorOrigin::from_wire_code(0), ErrorOrigin::Runtime);
1062 }
1063
1064 #[test]
1065 fn public_error_codes_are_sequential() {
1066 let first = ORDERED_ERROR_CODES
1067 .first()
1068 .expect("public error-code registry is non-empty")
1069 .raw();
1070
1071 assert_eq!(first, 1);
1072
1073 for (index, code) in ORDERED_ERROR_CODES.iter().enumerate() {
1074 let expected = first + u16::try_from(index).expect("test error-code index fits u16");
1075 assert_eq!(code.raw(), expected);
1076 assert_eq!(ErrorCode::known(code.raw()), Some(*code));
1077 assert!(code.is_known());
1078 }
1079
1080 let last = ORDERED_ERROR_CODES
1081 .last()
1082 .expect("public error-code registry is non-empty")
1083 .raw();
1084
1085 assert_eq!(last, 272);
1086 }
1087
1088 #[test]
1089 fn all_public_error_codes_round_trip_through_diagnostic_parts() {
1090 let first = ORDERED_ERROR_CODES
1091 .first()
1092 .expect("public error-code registry is non-empty")
1093 .raw();
1094 let last = ORDERED_ERROR_CODES
1095 .last()
1096 .expect("public error-code registry is non-empty")
1097 .raw();
1098
1099 for raw in first..=last {
1100 let code = ErrorCode::from_raw(raw);
1101 let diagnostic_code = code.diagnostic_code();
1102 let diagnostic_detail = code.diagnostic_detail();
1103 let rebuilt = ErrorCode::from_parts(diagnostic_code, diagnostic_detail);
1104
1105 assert_eq!(rebuilt.raw(), raw);
1106
1107 let diagnostic = code.diagnostic(ErrorOrigin::Runtime);
1108
1109 assert_eq!(diagnostic.code(), diagnostic_code);
1110 assert_eq!(diagnostic.detail(), diagnostic_detail.as_ref());
1111 assert_eq!(diagnostic.error_code().raw(), raw);
1112 }
1113 }
1114
1115 #[test]
1116 fn invalid_raw_error_codes_fail_closed_to_runtime_internal() {
1117 for raw in [0, 273, u16::MAX] {
1118 let code = ErrorCode::from_raw(raw);
1119
1120 assert_eq!(ErrorCode::known(raw), None);
1121 assert!(!code.is_known());
1122 assert_eq!(code.diagnostic_code(), DiagnosticCode::RuntimeInternal);
1123 assert_eq!(code.diagnostic_detail(), None);
1124 assert_eq!(code.class(), ErrorClass::Internal);
1125
1126 let diagnostic = code.diagnostic(ErrorOrigin::Query);
1127
1128 assert_eq!(diagnostic.code(), DiagnosticCode::RuntimeInternal);
1129 assert_eq!(diagnostic.origin(), ErrorOrigin::Query);
1130 assert_eq!(diagnostic.detail(), None);
1131 assert_eq!(diagnostic.error_code(), ErrorCode::RUNTIME_INTERNAL);
1132 }
1133 }
1134
1135 #[test]
1136 fn from_parts_requires_detail_to_match_broad_code() {
1137 let detail = Some(DiagnosticDetail::UnsupportedSqlFeature {
1138 feature: SqlFeatureCode::Join,
1139 });
1140
1141 assert_eq!(
1142 ErrorCode::from_parts(DiagnosticCode::QueryUnsupportedSqlFeature, detail),
1143 ErrorCode::SQL_FEATURE_JOIN
1144 );
1145 assert_eq!(
1146 ErrorCode::from_parts(DiagnosticCode::QueryPlan, detail),
1147 ErrorCode::QUERY_PLAN
1148 );
1149 }
1150
1151 #[test]
1152 fn detail_bearing_registry_entries_round_trip_directly() {
1153 assert!(!DETAIL_ERROR_CODES.is_empty());
1154
1155 for &(code, diagnostic_code, detail) in DETAIL_ERROR_CODES {
1156 assert_eq!(ErrorCode::from_parts(diagnostic_code, Some(detail)), code);
1157 assert_eq!(code.diagnostic_code(), diagnostic_code);
1158 assert_eq!(code.diagnostic_detail(), Some(detail));
1159 assert_eq!(detail.diagnostic_code(), diagnostic_code);
1160 }
1161 }
1162
1163 #[test]
1164 fn diagnostic_detail_reports_generated_broad_code() {
1165 let detail = DiagnosticDetail::UnsupportedSqlFeature {
1166 feature: SqlFeatureCode::Join,
1167 };
1168
1169 assert_eq!(
1170 detail.diagnostic_code(),
1171 DiagnosticCode::QueryUnsupportedSqlFeature
1172 );
1173 assert_eq!(format!("{detail:?}"), "65");
1174 }
1175
1176 #[test]
1177 fn public_error_codes_reconstruct_shifted_details() {
1178 assert_eq!(
1179 ErrorCode::QUERY_UNKNOWN_AGGREGATE_TARGET_FIELD.diagnostic_code(),
1180 DiagnosticCode::QueryUnknownAggregateTargetField
1181 );
1182 assert_eq!(
1183 ErrorCode::SQL_FEATURE_JOIN.diagnostic_detail(),
1184 Some(DiagnosticDetail::UnsupportedSqlFeature {
1185 feature: SqlFeatureCode::Join,
1186 })
1187 );
1188 assert_eq!(
1189 ErrorCode::QUERY_PROJECTION_NUMERIC_LITERAL_REQUIRED.diagnostic_detail(),
1190 Some(DiagnosticDetail::QueryProjection {
1191 reason: QueryProjectionCode::NumericLiteralRequired,
1192 })
1193 );
1194 assert_eq!(
1195 ErrorCode::QUERY_READ_PUBLIC_REQUIRES_LIMIT.diagnostic_detail(),
1196 Some(DiagnosticDetail::QueryReadAdmission {
1197 reason: QueryReadAdmissionCode::PublicQueryRequiresLimit,
1198 })
1199 );
1200 assert_eq!(
1201 ErrorCode::SQL_LOWERING_DISTINCT_ORDER_BY_PROJECTION.diagnostic_detail(),
1202 Some(DiagnosticDetail::SqlLowering {
1203 reason: SqlLoweringCode::DistinctOrderByProjection,
1204 })
1205 );
1206 assert_eq!(
1207 ErrorCode::SQL_WRITE_RETURNING_RESPONSE_TOO_LARGE.diagnostic_detail(),
1208 Some(DiagnosticDetail::SqlWriteBoundary {
1209 boundary: SqlWriteBoundaryCode::ReturningResponseTooLarge,
1210 })
1211 );
1212 assert_eq!(
1213 ErrorCode::SQL_WRITE_RETURNING_ROWS_TOO_MANY.diagnostic_detail(),
1214 Some(DiagnosticDetail::SqlWriteBoundary {
1215 boundary: SqlWriteBoundaryCode::ReturningRowsTooMany,
1216 })
1217 );
1218 }
1219}