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