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