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