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}
549
550impl fmt::Debug for RuntimeBoundaryCode {
551 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
552 fmt_compact_code(f, *self as u16)
553 }
554}
555
556#[repr(u16)]
564#[derive(Clone, Copy, Eq, Hash, PartialEq)]
565pub enum SqlFeatureCode {
566 AggregateFilterClause,
567 AlterStatementBeyondAlterTable,
568 AlterTableAddColumnDuplicateDefault,
569 AlterTableAddColumnModifiers,
570 AlterTableAddStatementBeyondAddColumn,
571 AlterTableAlterColumnDropUnsupportedAction,
572 AlterTableAlterColumnModifiers,
573 AlterTableAlterColumnSetUnsupportedAction,
574 AlterTableAlterColumnUnsupportedAction,
575 AlterTableAlterStatementBeyondAlterColumn,
576 AlterTableDropColumnIfExistsSyntax,
577 AlterTableDropColumnModifiers,
578 AlterTableDropStatementBeyondDropColumn,
579 AlterTableRenameColumnMissingTo,
580 AlterTableRenameColumnModifiers,
581 AlterTableRenameStatementBeyondRenameColumn,
582 AlterTableUnsupportedOperation,
583 ColumnAlias,
584 CreateIndexIfNotExistsSyntax,
585 CreateIndexKeyOrderingModifiers,
586 CreateIndexModifiers,
587 CreateStatementBeyondCreateIndex,
588 DescribeModifier,
589 DdlSchemaVersionDuplicateExpectedClause,
590 DdlSchemaVersionDuplicateSetClause,
591 DropIndexModifiers,
592 DropIndexIfExistsSyntax,
593 DropStatementBeyondDropIndex,
594 ExpressionIndexUnsupportedFunction,
595 Having,
596 Insert,
597 Join,
598 LikePatternBeyondTrailingPrefix,
599 LowerFieldPredicateUnsupported,
600 MultiStatementSql,
601 NestedAggregateInput,
602 NestedProjectionFunctionInArithmetic,
603 OrderByUnsupportedForm,
604 Other,
605 PredicateStartsWithFirstArgument,
606 QuotedIdentifiers,
607 ReturningUnsupportedShape,
608 ScalarFunctionExpressionPosition,
609 ScaleTakingNumericFunctionExpressionPosition,
610 SearchedCaseGroupedOrderBy,
611 ShowColumnsModifiers,
612 ShowEntitiesModifiers,
613 ShowIndexesModifiers,
614 ShowMemoryModifiers,
615 ShowStoresModifiers,
616 ShowUnsupportedCommand,
617 SimpleCaseExpression,
618 StandaloneLiteralProjectionItem,
619 SupportedGroupedOrderByExpressionFamily,
620 SupportedOrderByExpressionFamily,
621 UnionIntersectExcept,
622 UnsupportedFunctionNamespace,
623 Update,
624 UpperFieldPredicateUnsupported,
625 WindowFunction,
626 With,
627 NumericScaleFunctionArguments,
628 OrderByFieldNotOrderable,
629 ShowConstraintsModifiers,
630 AlterTableAddConstraintBeyondCheck,
631 AlterTableAddConstraintModifiers,
632 AlterTableDropConstraintIfExistsSyntax,
633 AlterTableDropConstraintModifiers,
634 AlterTableValidateBeyondConstraint,
635 AlterTableValidateConstraintModifiers,
636}
637
638impl fmt::Debug for SqlFeatureCode {
639 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
640 fmt_compact_code(f, *self as u16)
641 }
642}
643
644#[repr(u16)]
653#[derive(Clone, Copy, Eq, Hash, PartialEq)]
654pub enum SqlLoweringCode {
655 EntityMismatch,
656 SelectProjectionShape,
657 SelectDistinct,
658 DistinctOrderByProjection,
659 GlobalAggregateProjection,
660 GlobalAggregateGroupBy,
661 SelectGroupByShape,
662 GroupedProjectionExplicitListRequired,
663 GroupedProjectionAggregateRequired,
664 GroupedProjectionNonGroupField,
665 GroupedProjectionScalarAfterAggregate,
666 HavingRequiresGroupBy,
667 SelectHavingShape,
668 AggregateInputExpressions,
669 WhereExpressionShape,
670 ParameterPlacement,
671 SqlDdlExecutionUnsupported,
672}
673
674impl fmt::Debug for SqlLoweringCode {
675 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
676 fmt_compact_code(f, *self as u16)
677 }
678}
679
680#[repr(u16)]
688#[derive(Clone, Copy, Eq, Hash, PartialEq)]
689pub enum SqlSurfaceMismatchCode {
690 QueryRejectsInsert,
691 QueryRejectsUpdate,
692 QueryRejectsDelete,
693 MutationRejectsSelect,
694 MutationRejectsExplain,
695 MutationRejectsDescribe,
696 MutationRejectsShowIndexes,
697 MutationRejectsShowColumns,
698 MutationRejectsShowEntities,
699 MutationRejectsShowStores,
700 MutationRejectsShowMemory,
701 MutationRequiresExplicitUpdateIntent,
702 MutationRejectsShowConstraints,
703}
704
705impl fmt::Debug for SqlSurfaceMismatchCode {
706 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
707 fmt_compact_code(f, *self as u16)
708 }
709}
710
711#[repr(u16)]
719#[derive(Clone, Copy, Eq, Hash, PartialEq)]
720pub enum SqlWriteBoundaryCode {
721 PrimaryKeyLiteralShape,
722 PrimaryKeyLiteralIncompatible,
723 MissingPrimaryKey,
724 MissingRequiredFields,
725 ExplicitManagedField,
726 ExplicitGeneratedField,
727 InsertSelectRequiresScalar,
728 InsertSelectAggregateProjection,
729 InsertSelectWidthMismatch,
730 UpdatePrimaryKeyMutation,
731 InvalidFieldLiteral,
732 UnknownReturningField,
733 DuplicateReturningField,
734 UpdateMissingWherePredicate,
735 WriteOrderByUnsupportedShape,
736 ReturningResponseTooLarge,
737 ReturningRowsTooMany,
738 StagedRowsTooMany,
739 InsertDefaultRequiredField,
740 UpdateDefaultRequiredField,
741 UpdateDefaultDatabaseOwnedField,
742 ExactUpdateAssertionRequired,
743 ExactUpdateAssertionTooHigh,
744 ExactUpdateAffectedRowsExceeded,
745 ExactUpdateWindowUnsupported,
746 ExactUpdateScanBudgetExceeded,
747 ResumableUpdateWindowUnsupported,
748 ResumableUpdateReturningUnsupported,
749 ResumableUpdateRequiresJournaledStore,
750 ResumableUpdateAssignedFieldHasGlobalConstraint,
751 ResumableUpdateScopeDependsOnAssignedField,
752 ResumableUpdateScopeDependencyUnknown,
753 ResumableUpdateContinuationMalformed,
754 ResumableUpdateContinuationTargetMismatch,
755 ResumableUpdateContinuationSchemaMismatch,
756 ResumableUpdateContinuationScopeMismatch,
757 ResumableUpdateContinuationPatchMismatch,
758 ResumableUpdateContinuationBatchPolicyMismatch,
759 ResumableUpdateSingleRowResourceExceeded,
760 ResumableUpdateManagedFieldHasGlobalConstraint,
761 ResumableUpdateContinuationOperationMismatch,
762}
763
764impl fmt::Debug for SqlWriteBoundaryCode {
765 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
766 fmt_compact_code(f, *self as u16)
767 }
768}
769
770#[repr(u16)]
778#[derive(Clone, Copy, Eq, Hash, PartialEq)]
779pub enum SchemaDdlAdmissionCode {
780 MissingExpectedSchemaVersion,
781 MissingNextSchemaVersion,
782 StaleExpectedSchemaVersion,
783 InvalidExpectedSchemaVersion,
784 InvalidNextSchemaVersion,
785 AcceptedSchemaChangeWithoutVersionBump,
786 EmptyVersionBump,
787 VersionGap,
788 VersionRollback,
789 FingerprintMethodMismatch,
790 UnsupportedTransitionClass,
791 PhysicalRunnerMissing,
792 ValidationFailed,
793 PublicationRaceLost,
794 InvalidAddColumnDefault,
795 InvalidAlterColumnDefault,
796 GeneratedIndexDropRejected,
797 SchemaRewriteRequiresMigration,
798 SchemaTransitionBudgetExceeded,
799 GeneratedFieldDefaultChangeRejected,
800 GeneratedFieldNullabilityChangeRejected,
801 RowLayoutVersionExhausted,
802}
803
804impl fmt::Debug for SchemaDdlAdmissionCode {
805 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
806 fmt_compact_code(f, *self as u16)
807 }
808}
809
810#[repr(u16)]
812#[derive(Clone, Copy, Eq, Hash, PartialEq)]
813pub enum SchemaMigrationCode {
814 Unadopted,
815 MissingMigration,
816 VersionGap,
817 Downgrade,
818 EmptyEntityVersionBump,
819 DuplicateEntityTransition,
820 StaleAcceptedHead,
821 PlanChanged,
822 DuplicateRenameSource,
823 DuplicateRenameTarget,
824 UnknownFromObject,
825 UnknownToObject,
826 KindMismatch,
827 IdentityConflict,
828 IncompleteRenameCoverage,
829 UnexplainedSchemaDifference,
830 UnsupportedTransform,
831 TransformFinding,
832 UniqueIndexFinding,
833 RelationFinding,
834 ConstraintFinding,
835 PhysicalRunnerMissing,
836 MigrationInProgress,
837 AbortTooLate,
838 ProgressCorrupt,
839 CandidateMismatch,
840 PublicationRaceLost,
841}
842
843impl SchemaMigrationCode {
844 #[must_use]
846 pub const fn diagnostic_code(self) -> DiagnosticCode {
847 match self {
848 Self::StaleAcceptedHead
849 | Self::PlanChanged
850 | Self::IdentityConflict
851 | Self::MigrationInProgress
852 | Self::AbortTooLate
853 | Self::PublicationRaceLost => DiagnosticCode::RuntimeConflict,
854 Self::ProgressCorrupt | Self::CandidateMismatch => DiagnosticCode::RuntimeCorruption,
855 Self::Unadopted
856 | Self::MissingMigration
857 | Self::VersionGap
858 | Self::Downgrade
859 | Self::EmptyEntityVersionBump
860 | Self::DuplicateEntityTransition
861 | Self::DuplicateRenameSource
862 | Self::DuplicateRenameTarget
863 | Self::UnknownFromObject
864 | Self::UnknownToObject
865 | Self::KindMismatch
866 | Self::IncompleteRenameCoverage
867 | Self::UnexplainedSchemaDifference
868 | Self::UnsupportedTransform
869 | Self::TransformFinding
870 | Self::UniqueIndexFinding
871 | Self::RelationFinding
872 | Self::ConstraintFinding
873 | Self::PhysicalRunnerMissing => DiagnosticCode::RuntimeUnsupported,
874 }
875 }
876}
877
878impl fmt::Debug for SchemaMigrationCode {
879 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
880 fmt_compact_code(f, *self as u16)
881 }
882}
883
884#[remain::sorted]
891#[derive(Clone, Copy, Eq, PartialEq)]
892pub enum DiagnosticDetail {
893 QueryKind { kind: QueryErrorKind },
894 QueryProjection { reason: QueryProjectionCode },
895 QueryReadAdmission { reason: QueryReadAdmissionCode },
896 QueryResultShape { reason: QueryResultShapeCode },
897 RuntimeBoundary { boundary: RuntimeBoundaryCode },
898 RuntimeKind { kind: RuntimeErrorKind },
899 SchemaDdlAdmission { reason: SchemaDdlAdmissionCode },
900 SchemaMigration { reason: SchemaMigrationCode },
901 SqlLowering { reason: SqlLoweringCode },
902 SqlSurfaceMismatch { mismatch: SqlSurfaceMismatchCode },
903 SqlWriteBoundary { boundary: SqlWriteBoundaryCode },
904 UnsupportedSqlFeature { feature: SqlFeatureCode },
905}
906
907impl fmt::Debug for DiagnosticDetail {
908 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
909 fmt_compact_code(
910 f,
911 ErrorCode::from_parts(self.diagnostic_code(), Some(*self)).raw(),
912 )
913 }
914}
915
916#[derive(Clone, Eq, PartialEq)]
923pub struct Diagnostic {
924 code: DiagnosticCode,
925 origin: ErrorOrigin,
926 detail: Option<DiagnosticDetail>,
927}
928
929impl Diagnostic {
930 #[must_use]
932 pub const fn new(
933 code: DiagnosticCode,
934 origin: ErrorOrigin,
935 detail: Option<DiagnosticDetail>,
936 ) -> Self {
937 Self {
938 code,
939 origin,
940 detail,
941 }
942 }
943
944 #[must_use]
946 pub const fn from_code(code: DiagnosticCode) -> Self {
947 Self::new(code, code.origin(), None)
948 }
949
950 #[must_use]
952 pub const fn code(&self) -> DiagnosticCode {
953 self.code
954 }
955
956 #[must_use]
958 pub const fn class(&self) -> ErrorClass {
959 self.code.class()
960 }
961
962 #[must_use]
964 pub const fn origin(&self) -> ErrorOrigin {
965 self.origin
966 }
967
968 #[must_use]
970 pub const fn detail(&self) -> Option<&DiagnosticDetail> {
971 self.detail.as_ref()
972 }
973
974 #[must_use]
976 pub const fn error_code(&self) -> ErrorCode {
977 ErrorCode::from_parts(self.code, self.detail)
978 }
979}
980
981impl fmt::Debug for Diagnostic {
982 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
983 write!(f, "{}@{}", self.error_code().raw(), self.origin.wire_code())
984 }
985}
986
987fn fmt_compact_code(f: &mut fmt::Formatter<'_>, raw: u16) -> fmt::Result {
988 write!(f, "{raw}")
989}
990
991#[cfg(test)]
992mod tests {
993 use super::{
994 Diagnostic, DiagnosticCode, DiagnosticDetail, ErrorClass, ErrorCode, ErrorOrigin,
995 QueryProjectionCode, QueryReadAdmissionCode, SqlFeatureCode, SqlLoweringCode,
996 SqlWriteBoundaryCode,
997 registry::{DETAIL_ERROR_CODES, ORDERED_ERROR_CODES},
998 };
999
1000 #[test]
1001 fn diagnostic_from_code_uses_default_origin() {
1002 let diagnostic = Diagnostic::from_code(DiagnosticCode::QueryPlan);
1003
1004 assert_eq!(diagnostic.code(), DiagnosticCode::QueryPlan);
1005 assert_eq!(diagnostic.origin(), ErrorOrigin::Query);
1006 }
1007
1008 #[test]
1009 fn diagnostic_code_reports_broad_class() {
1010 assert_eq!(
1011 DiagnosticCode::QueryUnsupportedSqlFeature.class(),
1012 ErrorClass::Unsupported
1013 );
1014 assert_eq!(
1015 DiagnosticCode::QuerySqlSurfaceMismatch.class(),
1016 ErrorClass::Unsupported
1017 );
1018 assert_eq!(DiagnosticCode::QueryPlan.class(), ErrorClass::Query);
1019 assert_eq!(
1020 DiagnosticCode::StoreCorruption.class(),
1021 ErrorClass::Corruption
1022 );
1023 }
1024
1025 #[test]
1026 fn class_and_origin_wire_codes_round_trip() {
1027 for (class, raw) in [
1028 (ErrorClass::Query, 1),
1029 (ErrorClass::Corruption, 2),
1030 (ErrorClass::IncompatiblePersistedFormat, 3),
1031 (ErrorClass::NotFound, 4),
1032 (ErrorClass::Internal, 5),
1033 (ErrorClass::Conflict, 6),
1034 (ErrorClass::Unsupported, 7),
1035 (ErrorClass::InvariantViolation, 8),
1036 ] {
1037 assert_eq!(class.wire_code(), raw);
1038 assert_eq!(ErrorClass::from_wire_code(raw), Some(class));
1039 assert_eq!(format!("{class:?}"), raw.to_string());
1040 }
1041
1042 for (origin, raw) in [
1043 (ErrorOrigin::Cursor, 1),
1044 (ErrorOrigin::Executor, 2),
1045 (ErrorOrigin::Identity, 3),
1046 (ErrorOrigin::Index, 4),
1047 (ErrorOrigin::Interface, 5),
1048 (ErrorOrigin::Planner, 6),
1049 (ErrorOrigin::Query, 7),
1050 (ErrorOrigin::Recovery, 8),
1051 (ErrorOrigin::Response, 9),
1052 (ErrorOrigin::Runtime, 10),
1053 (ErrorOrigin::Serialize, 11),
1054 (ErrorOrigin::Store, 12),
1055 ] {
1056 assert_eq!(origin.wire_code(), raw);
1057 assert_eq!(ErrorOrigin::from_known_wire_code(raw), Some(origin));
1058 assert_eq!(ErrorOrigin::from_wire_code(raw), origin);
1059 assert_eq!(format!("{origin:?}"), raw.to_string());
1060 }
1061
1062 assert_eq!(ErrorClass::from_wire_code(0), None);
1063 assert_eq!(ErrorOrigin::from_known_wire_code(0), None);
1064 assert_eq!(ErrorOrigin::from_wire_code(0), ErrorOrigin::Runtime);
1065 }
1066
1067 #[test]
1068 fn public_error_codes_are_sequential() {
1069 let first = ORDERED_ERROR_CODES
1070 .first()
1071 .expect("public error-code registry is non-empty")
1072 .raw();
1073
1074 assert_eq!(first, 1);
1075
1076 for (index, code) in ORDERED_ERROR_CODES.iter().enumerate() {
1077 let expected = first + u16::try_from(index).expect("test error-code index fits u16");
1078 assert_eq!(code.raw(), expected);
1079 assert_eq!(ErrorCode::known(code.raw()), Some(*code));
1080 assert!(code.is_known());
1081 }
1082
1083 let last = ORDERED_ERROR_CODES
1084 .last()
1085 .expect("public error-code registry is non-empty")
1086 .raw();
1087
1088 assert_eq!(last, 273);
1089 }
1090
1091 #[test]
1092 fn all_public_error_codes_round_trip_through_diagnostic_parts() {
1093 let first = ORDERED_ERROR_CODES
1094 .first()
1095 .expect("public error-code registry is non-empty")
1096 .raw();
1097 let last = ORDERED_ERROR_CODES
1098 .last()
1099 .expect("public error-code registry is non-empty")
1100 .raw();
1101
1102 for raw in first..=last {
1103 let code = ErrorCode::from_raw(raw);
1104 let diagnostic_code = code.diagnostic_code();
1105 let diagnostic_detail = code.diagnostic_detail();
1106 let rebuilt = ErrorCode::from_parts(diagnostic_code, diagnostic_detail);
1107
1108 assert_eq!(rebuilt.raw(), raw);
1109
1110 let diagnostic = code.diagnostic(ErrorOrigin::Runtime);
1111
1112 assert_eq!(diagnostic.code(), diagnostic_code);
1113 assert_eq!(diagnostic.detail(), diagnostic_detail.as_ref());
1114 assert_eq!(diagnostic.error_code().raw(), raw);
1115 }
1116 }
1117
1118 #[test]
1119 fn invalid_raw_error_codes_fail_closed_to_runtime_internal() {
1120 for raw in [0, 274, u16::MAX] {
1121 let code = ErrorCode::from_raw(raw);
1122
1123 assert_eq!(ErrorCode::known(raw), None);
1124 assert!(!code.is_known());
1125 assert_eq!(code.diagnostic_code(), DiagnosticCode::RuntimeInternal);
1126 assert_eq!(code.diagnostic_detail(), None);
1127 assert_eq!(code.class(), ErrorClass::Internal);
1128
1129 let diagnostic = code.diagnostic(ErrorOrigin::Query);
1130
1131 assert_eq!(diagnostic.code(), DiagnosticCode::RuntimeInternal);
1132 assert_eq!(diagnostic.origin(), ErrorOrigin::Query);
1133 assert_eq!(diagnostic.detail(), None);
1134 assert_eq!(diagnostic.error_code(), ErrorCode::RUNTIME_INTERNAL);
1135 }
1136 }
1137
1138 #[test]
1139 fn from_parts_requires_detail_to_match_broad_code() {
1140 let detail = Some(DiagnosticDetail::UnsupportedSqlFeature {
1141 feature: SqlFeatureCode::Join,
1142 });
1143
1144 assert_eq!(
1145 ErrorCode::from_parts(DiagnosticCode::QueryUnsupportedSqlFeature, detail),
1146 ErrorCode::SQL_FEATURE_JOIN
1147 );
1148 assert_eq!(
1149 ErrorCode::from_parts(DiagnosticCode::QueryPlan, detail),
1150 ErrorCode::QUERY_PLAN
1151 );
1152 }
1153
1154 #[test]
1155 fn detail_bearing_registry_entries_round_trip_directly() {
1156 assert!(!DETAIL_ERROR_CODES.is_empty());
1157
1158 for &(code, diagnostic_code, detail) in DETAIL_ERROR_CODES {
1159 assert_eq!(ErrorCode::from_parts(diagnostic_code, Some(detail)), code);
1160 assert_eq!(code.diagnostic_code(), diagnostic_code);
1161 assert_eq!(code.diagnostic_detail(), Some(detail));
1162 assert_eq!(detail.diagnostic_code(), diagnostic_code);
1163 }
1164 }
1165
1166 #[test]
1167 fn diagnostic_detail_reports_generated_broad_code() {
1168 let detail = DiagnosticDetail::UnsupportedSqlFeature {
1169 feature: SqlFeatureCode::Join,
1170 };
1171
1172 assert_eq!(
1173 detail.diagnostic_code(),
1174 DiagnosticCode::QueryUnsupportedSqlFeature
1175 );
1176 assert_eq!(format!("{detail:?}"), "65");
1177 }
1178
1179 #[test]
1180 fn public_error_codes_reconstruct_shifted_details() {
1181 assert_eq!(
1182 ErrorCode::QUERY_UNKNOWN_AGGREGATE_TARGET_FIELD.diagnostic_code(),
1183 DiagnosticCode::QueryUnknownAggregateTargetField
1184 );
1185 assert_eq!(
1186 ErrorCode::SQL_FEATURE_JOIN.diagnostic_detail(),
1187 Some(DiagnosticDetail::UnsupportedSqlFeature {
1188 feature: SqlFeatureCode::Join,
1189 })
1190 );
1191 assert_eq!(
1192 ErrorCode::QUERY_PROJECTION_NUMERIC_LITERAL_REQUIRED.diagnostic_detail(),
1193 Some(DiagnosticDetail::QueryProjection {
1194 reason: QueryProjectionCode::NumericLiteralRequired,
1195 })
1196 );
1197 assert_eq!(
1198 ErrorCode::QUERY_READ_PUBLIC_REQUIRES_LIMIT.diagnostic_detail(),
1199 Some(DiagnosticDetail::QueryReadAdmission {
1200 reason: QueryReadAdmissionCode::PublicQueryRequiresLimit,
1201 })
1202 );
1203 assert_eq!(
1204 ErrorCode::SQL_LOWERING_DISTINCT_ORDER_BY_PROJECTION.diagnostic_detail(),
1205 Some(DiagnosticDetail::SqlLowering {
1206 reason: SqlLoweringCode::DistinctOrderByProjection,
1207 })
1208 );
1209 assert_eq!(
1210 ErrorCode::SQL_WRITE_RETURNING_RESPONSE_TOO_LARGE.diagnostic_detail(),
1211 Some(DiagnosticDetail::SqlWriteBoundary {
1212 boundary: SqlWriteBoundaryCode::ReturningResponseTooLarge,
1213 })
1214 );
1215 assert_eq!(
1216 ErrorCode::SQL_WRITE_RETURNING_ROWS_TOO_MANY.diagnostic_detail(),
1217 Some(DiagnosticDetail::SqlWriteBoundary {
1218 boundary: SqlWriteBoundaryCode::ReturningRowsTooMany,
1219 })
1220 );
1221 }
1222}